Browse Source

2021.11.02 VIP wallpadCall 통화 merge
add file

DESKTOP-UNEGUH3\MadeinLab_SW_02 3 years ago
parent
commit
4a157564e1
24 changed files with 10826 additions and 0 deletions
  1. 105 0
      WallPadCall/src/main/java/bssoft/stack/sip/BSSVideo.java
  2. 3855 0
      WallPadCall/src/main/java/bssoft/stack/sip/CMCore.java
  3. 21 0
      WallPadCall/src/main/java/bssoft/stack/sip/Frequent.java
  4. 36 0
      WallPadCall/src/main/java/bssoft/stack/sip/GetIpDns.java
  5. 82 0
      WallPadCall/src/main/java/bssoft/stack/sip/History.java
  6. 95 0
      WallPadCall/src/main/java/bssoft/stack/sip/RFC2833.java
  7. 328 0
      WallPadCall/src/main/java/bssoft/stack/sip/RTPCore.java
  8. 316 0
      WallPadCall/src/main/java/bssoft/stack/sip/SDPMedia.java
  9. 138 0
      WallPadCall/src/main/java/bssoft/stack/sip/SIPAUTHENTICATEHeader.java
  10. 330 0
      WallPadCall/src/main/java/bssoft/stack/sip/SIPCONTACTHeader.java
  11. 2511 0
      WallPadCall/src/main/java/bssoft/stack/sip/SIPCall.java
  12. 362 0
      WallPadCall/src/main/java/bssoft/stack/sip/SIPG711.java
  13. 225 0
      WallPadCall/src/main/java/bssoft/stack/sip/SIPHeader.java
  14. 268 0
      WallPadCall/src/main/java/bssoft/stack/sip/SIPHeaderParty.java
  15. 135 0
      WallPadCall/src/main/java/bssoft/stack/sip/SIPROUTEHeader.java
  16. 204 0
      WallPadCall/src/main/java/bssoft/stack/sip/SIPRequestLine.java
  17. 248 0
      WallPadCall/src/main/java/bssoft/stack/sip/SIPSdp.java
  18. 785 0
      WallPadCall/src/main/java/bssoft/stack/sip/SIPStack.java
  19. 124 0
      WallPadCall/src/main/java/bssoft/stack/sip/SIPVIAHeader.java
  20. 38 0
      WallPadCall/src/main/java/bssoft/stack/sip/SIPmd5.java
  21. 294 0
      WallPadCall/src/main/java/bssoft/stack/sip/UPDATEHeaders.java
  22. 11 0
      WallPadCall/src/main/java/bssoft/stack/sip/UserDial.java
  23. 87 0
      WallPadCall/src/main/java/bssoft/stack/sip/stackKey.java
  24. 228 0
      WallPadCall/src/main/java/bssoft/stack/sip/videoEnc.java

+ 105 - 0
WallPadCall/src/main/java/bssoft/stack/sip/BSSVideo.java

@@ -0,0 +1,105 @@
+package bssoft.stack.sip;
+
+import java.util.Date;
+
+public class BSSVideo {
+    public static int HNS_SERVICE_NONE = 9;
+
+    public static int HNS_SERVICE_DOOR = 0;
+
+    public static int HNS_SERVICE_LOBBY = 1;
+
+    public static int HNS_SERVICE_GUARD = 2;
+
+    public static int HNS_SERVICE_NEIGHBOR = 3;
+
+    public static int HNS_SERVICE_TELEPHONE = 4;
+
+    public static int HNS_SERVICE_HISTORY = 5;
+
+    public static int HNS_SERVICE_PICTURE = 6;
+
+    public static int HNS_SERVICE_ORIGINATOR_SELECTED = HNS_SERVICE_NEIGHBOR;
+
+    public static int HNS_SERVICE_RECEIVER_SELECTED = HNS_SERVICE_NONE;
+
+    public static String HNS_PREFIX_LOBBY = "HNSLOBBY.";
+
+    public static String HNS_PREFIX_GUARD = "HNSGUARD.";
+
+    public static String HNS_PREFIX_NEIGHBOR = "HNSNEIGHBOR.";
+
+    public static String HNS_POSTFIX_LOBBY = ".HNSLOBBY";
+
+    public static String HNS_POSTFIX_GUARD = ".HNSGUARD";
+
+    public static String HNS_POSTFIX_NEIGHBOR = ".HNSNEIGHBOR";
+
+    public static int codec = 98;
+
+    public static int VIDEO_PTIME = 200;
+
+    public static boolean bInitializeMode = false;
+
+    public static int camera_width = 320;
+
+    public static int camera_height = 240;
+
+    public static int decode_width = 320;
+
+    public static int decode_height = 240;
+
+    public static int yuv_width = 320;
+
+    public static int yuv_height = 240;
+
+    public static int yuv_offset_x = 0;
+
+    public static int yuv_offset_y = 0;
+
+    public static int ENCODE_FRAME_RATE = 30;
+
+    public static int KEY_FRAME_RATE = 15;
+
+    public static int KEY_I_FRAME_INTERVAL = 5;
+
+    public static int KEY_BIT_RATE = 1440000;
+
+    public static boolean bService = false;
+
+    public static boolean bViewme = false;
+
+    public static int displaySizeType = 0;
+
+    public static boolean bSending = false;
+
+    public static boolean bFrameSet = false;
+
+    public static int iFrames = 0;
+
+    public static String remoteIp = null;
+
+    public static int remotePort = 3002;
+
+    public static int iRunmode = 0;
+
+    public static boolean bVideoEncoding = false;
+
+    public static boolean bVideoDecoding = false;
+
+    public static boolean bSurfaceoutput = true;
+
+    public static boolean bCover = true;
+
+    public static boolean bRemoteview = false;
+
+    public static Date dateVideoincoming = new Date();
+
+    public static int incurtenLength = 2000;
+
+    public static int outcurtenLength = 1000;
+
+    public static boolean bVideoMute = false;
+
+    public static boolean bProgressvideooffer = false;
+}

+ 3855 - 0
WallPadCall/src/main/java/bssoft/stack/sip/CMCore.java

@@ -0,0 +1,3855 @@
+package bssoft.stack.sip;
+
+import android.util.Log;
+
+import java.util.Date;
+import java.util.StringTokenizer;
+import java.util.Timer;
+
+public class CMCore {
+    String TAG = "CMCore";
+
+    public String commandLine = null;
+
+    public String viaH = null;
+
+    public String maxforwardH = null;
+
+    public String contactH = null;
+
+    public String toH = null;
+
+    public String fromH = null;
+
+    public String callidH = null;
+
+    public String cseqH = null;
+
+    public String expiresH = null;
+
+    public String allowH = null;
+
+    public String useragentH = null;
+
+    public String contentlengthH = null;
+
+    public String authorizationH = null;
+
+    public String serverIp = null;
+
+    public int serverPort = 5060;
+
+    public String serverDomain = null;
+
+    public String id = null;
+
+    public String cid = null;
+
+    public String authid = null;
+
+    public String authpassword = null;
+
+    public String localIp = null;
+
+    public String fromTag = null;
+
+    public String callId = null;
+
+    public int localPort = 5060;
+
+    public byte[] byteAddress = null;
+
+    public int CSEQ_NUMBER = SIPStack.SIP_SEQUENCE_REGISTER;
+
+    public int regState = SIPStack.SIP_REGSTATE_IDLE;
+
+    public Date regTime = new Date();
+
+    public Date callTime = new Date();
+
+    public int expiresSeconds = 60;
+
+    public int repeatRegisterCount = 0;
+
+    public int registerNonceCount = 0;
+
+    public String ifIp = null;
+
+    public int ifPort = 5060;
+
+    public String previfIp = null;
+
+    public int previfPort = 5060;
+
+    public boolean bInterfaceChanged = false;
+
+    public String message = null;
+
+    public int serviceMode = SIPStack.SIP_SERVICEMODE_BASIC;
+
+    public boolean bRequestReadySet = false;
+
+    public Timer SIGNALCTRLTimer = null;
+
+    public Thread SIGNALCTRLThread = null;
+
+    public boolean SIGNALCTRLRunning = false;
+
+    public int ctrlIndex = 0;
+
+    public Date ctrlIntervalTimer = new Date();
+
+    public Date netcheckIntervalTimer = new Date();
+
+    public Date registStatusTimer = new Date();
+
+    public static Date pauseTime = new Date();
+
+    public static boolean bPausing = true;
+
+    public static final int BSSSIPStun_ICONTROLS_REGISTER = 1;
+
+    public static final int BSSSIPStun_ICONTROLS_UNREGISTER = 2;
+
+    public static final int BSSSIPStun_ICONTROLS_SET_INT_VALUE = 3;
+
+    public static final int BSSSIPStun_ICONTROLS_SET_STRING_VALUE = 4;
+
+    public static final int BSSSIPStun_ICONTROLS_CM_UPDATESTATUS_TRUE = 10;
+
+    public static final int BSSSIPStun_ICONTROLS_CM_UPDATESTATUS_FALSE = 11;
+
+    public static final int BSSSIPStun_ICONTROLS_CM_VIDEOSET_TRUE = 12;
+
+    public static final int BSSSIPStun_ICONTROLS_CM_VIDEOSET_FALSE = 13;
+
+    public static final int BSSSIPStun_ICONTROLS_CM_INCOMINGCALL = 14;
+
+    public static final int BSSSIPStun_ICONTROLS_CM_CALLCONNECTED = 15;
+
+    public static final int BSSSIPStun_ICONTROLS_CM_SHUTDOWNAPPLICATION = 16;
+
+    public static final int BSSSIPStun_ICONTROLS_CM_BACKGROUNDINCOMINGCALL = 17;
+
+    public static final int BSSSIPStun_ICONTROLS_CM_VIBRATOR_TRUE = 18;
+
+    public static final int BSSSIPStun_ICONTROLS_CM_VIBRATOR_FALSE = 19;
+
+    public static final int BSSSIPStun_ICONTROLS_CM_REGISTSTATUS_TRUE = 20;
+
+    public static final int BSSSIPStun_ICONTROLS_CM_REGISTSTATUS_FALSE = 21;
+
+    public static final int BSSSIPStun_ICONTROLS_CM_RINGBACKTONE_TRUE = 22;
+
+    public static final int BSSSIPStun_ICONTROLS_CM_RINGBACKTONE_FALSE = 23;
+
+    public static final int BSSSIPStun_ICONTROLS_CM_CALLEND_TRUE = 24;
+
+    public static final int BSSSIPStun_ICONTROLS_CM_CALLEND_FALSE = 25;
+
+    public static final int BSSSIPStun_ICONTROLS_CM_OUTBANDDTMF = 26;
+
+    public static final int BSSSIPStun_ICONTROLS_CM_PADNUMBER = 27;
+
+    public static final int BSSSIPStun_ICONTROLS_CM_PADTYPE = 28;
+
+    public static final int BSSSIPStun_ICONTROLS_CM_CALLNEIGHBOR = 29;
+
+    public static final int BSSSIPStun_ICONTROLS_CM_CALLGUARD = 30;
+
+    public static final int BSSSIPStun_ICONTROLS_CM_CALLTIME = 31;
+
+    public static final int BSSSIPStun_ICONTROLS_CM_INCOMINGMULTICALL = 32;
+
+    public static final int BSSSIPStun_ICONTROLS_CM_ENDMULTICALL = 33;
+
+    public static final int BSSSIPStun_ICONTROLS_CM_NORMALIZEMULTICALL = 34;
+
+    public static final int BSSSIPStun_ICONTROLS_CM_CANCELMULTICALL = 35;
+
+    public static final int BSSSIPStun_ICONTROLS_CM_OUTCALLFAIL = 36;
+
+    public static final int BSSSIPStun_ICONTROLS_DIALER_ACCEPTMULTICALL = 40;
+
+    public static final int BSSSIPStun_ICONTROLS_DIALER_REJECTMULTICALL = 41;
+
+    public static final int BSSSIPStun_ICONTROLS_DIALER_CANCELMULTICALL = 42;
+
+    public static final int BSSSIPStun_ICONTROLS_DIALER_COMMAND = 43;
+
+    public static final int BSSSIPStun_ICONTROLS_DIALER_FORWARD = 44;
+
+    public static final int BSSSIPStun_ICONTROLS_CONTACT_CALLNEIGHBOR = 50;
+
+    public static final int BSSSIPStun_ICONTROLS_CONTACT_CALLGUARD = 51;
+
+    public static final int BSSSIPStun_ICONTROLS_BLOCK_INVITE_MSG = 100;
+
+    public static final int BSSSIPStun_ICONTROLS_PAUSING_DURATION = 1000;
+
+    public static boolean bDialerActive = false;
+
+    public CMCore() {
+        System.out.println("[CMCore] ========== START ==========");
+        if (!SIPStack.bStackLicensed) {
+            System.out.println("라이슨스키를 설정하세요.");
+                    //System.exit(0);
+        }
+        this.commandLine = null;
+        this.viaH = null;
+        this.maxforwardH = null;
+        this.contactH = null;
+        this.toH = null;
+        this.fromH = null;
+        this.callidH = null;
+        this.cseqH = null;
+        this.expiresH = null;
+        this.allowH = null;
+        this.useragentH = null;
+        this.contentlengthH = null;
+        this.authorizationH = null;
+        this.serverIp = null;
+        this.serverPort = 5060;
+        this.serverDomain = null;
+        this.id = null;
+        this.cid = null;
+        this.authid = null;
+        this.authpassword = null;
+        this.localIp = null;
+        this.fromTag = null;
+        this.callId = null;
+        this.localPort = 5060;
+        this.byteAddress = null;
+        this.CSEQ_NUMBER = SIPStack.SIP_SEQUENCE_REGISTER;
+        this.regState = SIPStack.SIP_REGSTATE_IDLE;
+        this.regTime = new Date();
+        this.callTime = new Date();
+        this.expiresSeconds = 60;
+        this.repeatRegisterCount = 0;
+        this.registerNonceCount = 0;
+        this.ifIp = null;
+        this.ifPort = 5060;
+        this.previfIp = null;
+        this.previfPort = 5060;
+        this.bInterfaceChanged = false;
+        this.message = null;
+        this.serviceMode = SIPStack.SIP_SERVICEMODE_BASIC;
+        this.bRequestReadySet = false;
+        this.SIGNALCTRLTimer = null;
+        this.SIGNALCTRLThread = null;
+        this.SIGNALCTRLRunning = false;
+        this.ctrlIndex = 0;
+        this.ctrlIntervalTimer = new Date();
+        this.netcheckIntervalTimer = new Date();
+        this.registStatusTimer = new Date();
+    }
+
+    public void action_0(byte[] byteLocalip, int localport, byte[] byteServerip, int serverport, byte[] byteServerdomain, byte[] byteId, byte[] byteCid, byte[] byteAuthid, byte[] byteAuthpassword) {
+        this.byteAddress = this.byteAddress;
+        this.localIp = new String(byteLocalip, 0, 0, byteLocalip.length);
+        this.localPort = localport;
+        SIPStack.localSdpIp = new String(byteLocalip, 0, 0, byteLocalip.length);
+        if (SIPStack.usePrivateWiMax && (SIPStack.isInternetWiMax || SIPStack.isInternetMobile) && !SIPStack.isPrivateIp(SIPStack.localSdpIp))
+            SIPStack.localSdpIp = "192.168.10.2";
+        this.ifIp = new String(byteLocalip, 0, 0, byteLocalip.length);
+        this.ifPort = this.localPort;
+        this.serverIp = new String(byteServerip, 0, 0, byteServerip.length);
+        this.serverPort = serverport;
+        this.serverDomain = new String(byteServerdomain, 0, 0, byteServerdomain.length);
+        if (this.serverDomain == null || this.serverDomain.length() == 0)
+            this.serverDomain = new String(this.serverIp);
+        this.id = new String(byteId, 0, 0, byteId.length);
+        this.cid = new String(byteCid, 0, 0, byteCid.length);
+        if (this.cid.length() < 7 || this.cid.length() == 0)
+            this.cid = new String(this.id);
+        this.authid = new String(byteAuthid, 0, 0, byteAuthid.length);
+        this.authpassword = new String(byteAuthpassword, 0, 0, byteAuthpassword.length);
+        this.commandLine = "REGISTER sip:" + this.serverDomain + ":" + this.serverPort + " SIP/2.0";
+        Date today = new Date();
+        this.viaH = "Via: SIP/2.0/UDP " + this.localIp + ":" + this.localPort + ";branch=" + SIPStack.getViaBranch() + ";rport";
+        this.maxforwardH = "Max-Forwards: 70";
+        this.contactH = "Contact: <sip:" + this.id + "@" + this.localIp + ":" + this.localPort + ">";
+        this.toH = "To: \"" + this.id + "\"<sip:" + this.id + "@" + this.serverDomain + ":" + this.serverPort + ">";
+        this.fromTag = SIPStack.newTag();
+        this.fromH = "From: \"" + this.id + "\"<sip:" + this.id + "@" + this.serverDomain + ":" + this.serverPort + ">;tag=" + this.fromTag;
+        this.callId = String.valueOf(SIPStack.BSSMD5Get(this.viaH)) + SIPStack.BSSMD5Get("1198602188") + today.getSeconds() + ".";
+        this.callidH = "Call-ID: " + this.callId;
+        if (this.CSEQ_NUMBER > 65556)
+            this.CSEQ_NUMBER = 0;
+        SIPStack.SIP_SEQUENCE_REGISTER = this.CSEQ_NUMBER;
+        this.cseqH = "CSeq: " + this.CSEQ_NUMBER + " REGISTER";
+        this.expiresH = "Expires: " + this.expiresSeconds;
+        this.allowH = "Allow: INVITE, ACK, CANCEL, OPTIONS, BYE, REFER, NOTIFY, MESSAGE, SUBSCRIBE, INFO";
+        this.useragentH = "User-Agent: KwangHaeSoft SmartSip release 0100o";
+        this.contentlengthH = "Content-Length: 0";
+        this.message = String.valueOf(this.commandLine) + SIPStack.SIP_LINE_END +
+                this.viaH + SIPStack.SIP_LINE_END +
+                this.maxforwardH + SIPStack.SIP_LINE_END +
+                this.contactH + SIPStack.SIP_LINE_END +
+                this.fromH + SIPStack.SIP_LINE_END +
+                this.toH + SIPStack.SIP_LINE_END +
+                this.callidH + SIPStack.SIP_LINE_END +
+                this.cseqH + SIPStack.SIP_LINE_END +
+                this.expiresH + SIPStack.SIP_LINE_END +
+                this.allowH + SIPStack.SIP_LINE_END +
+                this.useragentH + SIPStack.SIP_LINE_END +
+                this.contentlengthH + SIPStack.SIP_LINE_DOUBLEEND;
+        if (SIPStack.bUseCtrlTimer) {
+            if (this.SIGNALCTRLTimer != null)
+                this.SIGNALCTRLTimer.cancel();
+        } else {
+            if (this.SIGNALCTRLThread != null)
+                this.SIGNALCTRLThread.interrupt();
+            this.SIGNALCTRLRunning = false;
+        }
+        this.SIGNALCTRLTimer = new Timer();
+    }
+
+    public void action_1(byte[] byteAddress, byte[] byteLocalip, int localport, String strServerHost, int serverport, String strServerDomain, byte[] byteId, byte[] byteCid, byte[] byteAuthid, byte[] byteAuthpassword) {
+        byteAddress = byteAddress;
+        this.localIp = new String(byteLocalip, 0, 0, byteLocalip.length);
+        this.localPort = localport;
+        SIPStack.localSdpIp = this.localIp;
+        this.ifIp = new String(byteLocalip, 0, 0, byteLocalip.length);
+        this.ifPort = this.localPort;
+        this.serverPort = serverport;
+        SIPStack.ipdns.bSipAddressResolved = false;
+        SIPStack.ipdns.sipServerHost = "";
+        this.serverDomain = "";
+        this.serverIp = "";
+        SIPStack.ipdns.sipTry = 0;
+        if (strServerDomain != null && strServerDomain.length() > 0)
+            this.serverDomain = new String(strServerDomain);
+        if (strServerHost != null && strServerHost.length() > 0) {
+            SIPStack.ipdns.sipServerHost = strServerHost;
+        } else {
+            SIPStack.ipdns.bSipAddressResolved = true;
+        }
+        this.id = new String(byteId, 0, 0, byteId.length);
+        this.cid = new String(byteCid, 0, 0, byteCid.length);
+        if (this.cid.length() < 7 || this.cid.length() == 0)
+            this.cid = new String(this.id);
+        this.authid = new String(byteAuthid, 0, 0, byteAuthid.length);
+        this.authpassword = new String(byteAuthpassword, 0, 0, byteAuthpassword.length);
+        this.commandLine = "REGISTER sip:" + this.serverDomain + ":" + this.serverPort + " SIP/2.0";
+        Date today = new Date();
+        this.viaH = "Via: SIP/2.0/UDP " + this.localIp + ":" + this.localPort + ";branch=" + SIPStack.getViaBranch() + ";rport";
+        this.maxforwardH = "Max-Forwards: 70";
+        if (this.ifIp != null && this.ifIp.length() > 0 && this.ifPort > 0) {
+            this.contactH = "Contact: <sip:" + this.id + "@" + this.ifIp + ":" + this.ifPort + ">";
+        } else {
+            this.contactH = "Contact: <sip:" + this.id + "@" + this.localIp + ":" + this.localPort + ">";
+        }
+        this.toH = "To: \"" + this.id + "\"<sip:" + this.id + "@" + this.serverDomain + ":" + this.serverPort + ">";
+        this.fromTag = SIPStack.newTag();
+        this.fromH = "From: \"" + this.id + "\"<sip:" + this.id + "@" + this.serverDomain + ":" + this.serverPort + ">;tag=" + this.fromTag;
+        this.callId = String.valueOf(SIPStack.BSSMD5Get(this.viaH)) + SIPStack.BSSMD5Get("1198602188") + today.getSeconds() + ".";
+        this.callidH = "Call-ID: " + this.callId;
+        if (this.CSEQ_NUMBER > 65556)
+            this.CSEQ_NUMBER = 0;
+        SIPStack.SIP_SEQUENCE_REGISTER = this.CSEQ_NUMBER;
+        this.cseqH = "CSeq: " + this.CSEQ_NUMBER + " REGISTER";
+        this.expiresH = "Expires: " + this.expiresSeconds;
+        this.allowH = "Allow: INVITE, ACK, CANCEL, OPTIONS, BYE, REFER, NOTIFY, MESSAGE, SUBSCRIBE, INFO";
+        this.useragentH = "User-Agent: " + SIPStack.USER_AGENT;
+        this.contentlengthH = "Content-Length: 0";
+        this.message = String.valueOf(this.commandLine) + SIPStack.SIP_LINE_END +
+                this.viaH + SIPStack.SIP_LINE_END +
+                this.maxforwardH + SIPStack.SIP_LINE_END +
+                this.contactH + SIPStack.SIP_LINE_END +
+                this.fromH + SIPStack.SIP_LINE_END +
+                this.toH + SIPStack.SIP_LINE_END +
+                this.callidH + SIPStack.SIP_LINE_END +
+                this.cseqH + SIPStack.SIP_LINE_END +
+                this.expiresH + SIPStack.SIP_LINE_END +
+                this.allowH + SIPStack.SIP_LINE_END +
+                this.useragentH + SIPStack.SIP_LINE_END +
+                this.contentlengthH + SIPStack.SIP_LINE_DOUBLEEND;
+        if (SIPStack.bUseCtrlTimer) {
+            if (this.SIGNALCTRLTimer != null)
+                this.SIGNALCTRLTimer.cancel();
+        } else {
+            if (this.SIGNALCTRLThread != null)
+                this.SIGNALCTRLThread.interrupt();
+            this.SIGNALCTRLRunning = false;
+        }
+        this.SIGNALCTRLTimer = new Timer();
+    }
+
+    public void action_2(String strId, String strCid, String strAuthid, String strAuthpassword, String strServerHost, String strServerDomain, int serverport) {
+        this.serverIp = SIPStack.getIPV4(strServerHost);
+        if (this.serverIp == null)
+            this.serverIp = "";
+        if (strServerDomain == null || strServerDomain.length() == 0) {
+            this.serverDomain = new String(this.serverIp);
+        } else {
+            this.serverDomain = new String(strServerDomain);
+        }
+        this.serverPort = serverport;
+        this.id = new String(strId);
+        this.cid = new String(strCid);
+        this.authid = new String(strAuthid);
+        this.authpassword = new String(strAuthpassword);
+        this.regState = SIPStack.SIP_REGSTATE_REGISTERING;
+    }
+
+    public boolean action_net_0() {
+        try {
+            if (!SIPStack.ipdns.bSipAddressResolved &&
+                    SIPStack.ipdns.sipServerHost != null &&
+                    SIPStack.ipdns.sipServerHost.length() > 0) {
+                this.serverIp = SIPStack.getIPV4(SIPStack.ipdns.sipServerHost);
+                SIPStack.ipdns.sipTry++;
+                if (this.serverIp == null) {
+                    this.serverIp = "";
+                } else {
+                    SIPStack.ipdns.bSipAddressResolved = true;
+                }
+                if (this.serverDomain == null || this.serverDomain.length() == 0)
+                    this.serverDomain = new String(SIPStack.ipdns.sipServerHost);
+                if (this.serverIp != null && this.serverIp.length() > 0) {
+                    this.regState = SIPStack.SIP_REGSTATE_REGISTERING;
+                    return true;
+                }
+            }
+            return false;
+        } catch (Exception exception) {
+            return false;
+        }
+    }
+
+    public void action_net_1(String host) {
+        try {
+            if (host != null && host.length() > 0) {
+                String ip = SIPStack.getIPV4(host);
+                if (ip != null && ip.length() > 0)
+                    SIPStack.networkStatus = SIPStack.SIP_NETIF_AVAILABLE;
+                if (ip != null && ip.length() > 0 && ip.compareToIgnoreCase(this.localIp) != 0) {
+                    this.localIp = new String(ip);
+                    if (SIPStack.usePrivateWiMax && (
+                            SIPStack.isInternetWiMax || SIPStack.isInternetMobile) &&
+                            !SIPStack.isPrivateIp(ip)) {
+                        SIPStack.localSdpIp = "192.168.10.2";
+                    } else {
+                        SIPStack.localSdpIp = new String(ip);
+                    }
+                    if (this.ifIp == null || this.ifIp.length() == 0 || this.ifPort <= 0) {
+                        this.ifIp = new String(this.localIp);
+                        this.ifPort = SIPStack.SIP_LOCAL_PORT;
+                    }
+                } else if (ip == null || ip.length() == 0) {
+                    this.localIp = "127.0.0.1";
+                    SIPStack.localSdpIp = "127.0.0.1";
+                    SIPStack.networkStatus = SIPStack.SIP_NETIF_UNAVAILABLE;
+                }
+            } else if (host == null || host.length() == 0) {
+                this.localIp = "127.0.0.1";
+                SIPStack.localSdpIp = "127.0.0.1";
+                SIPStack.networkStatus = SIPStack.SIP_NETIF_UNAVAILABLE;
+            }
+        } catch (Exception exception) {}
+    }
+
+    public boolean action_net_2(String host) {
+        try {
+            if (host != null && host.length() > 0) {
+                String ip = SIPStack.getIPV4(host);
+                if (ip != null && ip.length() > 0)
+                    SIPStack.networkStatus = SIPStack.SIP_NETIF_AVAILABLE;
+                if (ip != null && ip.length() > 0 && ip.compareToIgnoreCase(this.localIp) != 0) {
+                    this.localIp = new String(ip);
+                    if (SIPStack.usePrivateWiMax && (
+                            SIPStack.isInternetWiMax || SIPStack.isInternetMobile) &&
+                            !SIPStack.isPrivateIp(ip)) {
+                        SIPStack.localSdpIp = "192.168.10.2";
+                    } else {
+                        SIPStack.localSdpIp = new String(ip);
+                    }
+                    this.ifIp = new String(this.localIp);
+                    this.ifPort = SIPStack.SIP_LOCAL_PORT;
+                    this.authorizationH = "";
+                    return true;
+                }
+                if (ip == null || ip.length() == 0) {
+                    this.localIp = "127.0.0.1";
+                    SIPStack.localSdpIp = "127.0.0.1";
+                    SIPStack.networkStatus = SIPStack.SIP_NETIF_UNAVAILABLE;
+                }
+            } else if (host == null || host.length() == 0) {
+                this.localIp = "127.0.0.1";
+                SIPStack.localSdpIp = "127.0.0.1";
+                SIPStack.networkStatus = SIPStack.SIP_NETIF_UNAVAILABLE;
+            }
+            return false;
+        } catch (Exception exception) {
+            return false;
+        }
+    }
+
+    public boolean action_net_3(String host) {
+        try {
+            if (host != null && host.length() > 0) {
+                String ip = SIPStack.getIPV4(host);
+                if (ip != null && ip.length() > 0)
+                    SIPStack.networkStatus = SIPStack.SIP_NETIF_AVAILABLE;
+                if (ip != null && ip.length() > 0 && ip.compareToIgnoreCase(this.localIp) != 0) {
+                    this.localIp = new String(ip);
+                    if (SIPStack.usePrivateWiMax && (
+                            SIPStack.isInternetWiMax || SIPStack.isInternetMobile) &&
+                            !SIPStack.isPrivateIp(ip)) {
+                        SIPStack.localSdpIp = "192.168.10.2";
+                    } else {
+                        SIPStack.localSdpIp = new String(ip);
+                    }
+                    this.bInterfaceChanged = true;
+                    this.previfIp = this.ifIp;
+                    this.previfPort = this.ifPort;
+                    this.ifIp = new String(this.localIp);
+                    this.ifPort = SIPStack.SIP_LOCAL_PORT;
+                    return true;
+                }
+                if (ip == null || ip.length() == 0) {
+                    this.localIp = "127.0.0.1";
+                    SIPStack.localSdpIp = "127.0.0.1";
+                    SIPStack.networkStatus = SIPStack.SIP_NETIF_UNAVAILABLE;
+                }
+            } else if (host == null || host.length() == 0) {
+                this.localIp = "127.0.0.1";
+                SIPStack.localSdpIp = "127.0.0.1";
+                SIPStack.networkStatus = SIPStack.SIP_NETIF_UNAVAILABLE;
+            }
+            return false;
+        } catch (Exception exception) {
+            return false;
+        }
+    }
+
+    public SIPCONTACTHeader action_reg_0(String message) {
+        try {
+            String requestUri = "sip:" + this.id + "@" + this.localIp + ":" + this.localPort;
+            if (this.ifIp != null &&
+                    this.ifIp.length() > 0 &&
+                    this.ifPort > 0)
+                if (this.bInterfaceChanged) {
+                    requestUri = "sip:" + this.id + "@" + this.previfIp + ":" + this.previfPort;
+                } else {
+                    requestUri = "sip:" + this.id + "@" + this.ifIp + ":" + this.ifPort;
+                }
+            return new SIPCONTACTHeader(message, requestUri);
+        } catch (Exception exception) {
+            return null;
+        }
+    }
+
+    public boolean action_reg_1(String message) {
+        try {
+            SIPVIAHeader viaHeader = new SIPVIAHeader(message);
+            if (viaHeader.flag && viaHeader.rportService &&
+                    viaHeader.rport > 0 && viaHeader.received.length() > 0)
+                if (this.ifIp == null ||
+                        this.ifIp.length() == 0 ||
+                        this.ifPort <= 0 ||
+                        this.ifIp.compareToIgnoreCase(viaHeader.received) != 0 ||
+                        this.ifPort != viaHeader.rport) {
+                    this.bInterfaceChanged = true;
+                    this.previfIp = this.ifIp;
+                    this.previfPort = this.ifPort;
+                    this.ifIp = new String(viaHeader.received);
+                    this.ifPort = viaHeader.getRport();
+                    return true;
+                }
+            return false;
+        } catch (Exception exception) {
+            return false;
+        }
+    }
+
+    public boolean action_reg_2(String message) {
+        try {
+            this.authorizationH = "";
+            SIPHeader sipHeader = new SIPHeader(message, SIPStack.SIP_HEADERTYPE_WWWAUTHENTICATE);
+            if (sipHeader == null || !sipHeader.flag)
+                sipHeader = new SIPHeader(message, SIPStack.SIP_HEADERTYPE_WwwAUTHENTICATE);
+            if (sipHeader != null && sipHeader.flag) {
+                SIPAUTHENTICATEHeader authHeader =
+                        new SIPAUTHENTICATEHeader(sipHeader.header, SIPStack.SIP_HEADERTYPE_WWWAUTHENTICATE);
+                if (authHeader == null || !authHeader.flag)
+                    authHeader = new SIPAUTHENTICATEHeader(sipHeader.header, SIPStack.SIP_HEADERTYPE_WwwAUTHENTICATE);
+                if (authHeader != null && authHeader.flag)
+                    if (authHeader.nonceValue.length() > 0 && authHeader.realmValue.length() > 0) {
+                        String qop = authHeader.qopValue;
+                        String uri = "sip:" + this.serverDomain + ":" + this.serverPort;
+                        this.authorizationH = getAuthorizationHeader(
+                                qop,
+                                this.authid,
+                                authHeader.realmValue,
+                                this.authpassword, uri,
+                                authHeader.nonceValue,
+                                SIPStack.SIP_METHODTYPE_REGISTER);
+                        return true;
+                    }
+            }
+            return false;
+        } catch (Exception exception) {
+            return false;
+        }
+    }
+
+    public boolean action_reg_3(String message) {
+        try {
+            this.regState = SIPStack.SIP_REGSTATE_UNAUTHORIZED;
+            this.authorizationH = "";
+            SIPHeader sipHeader = new SIPHeader(message, SIPStack.SIP_HEADERTYPE_PROXYAUTHENTICATE);
+            if (sipHeader != null && sipHeader.flag) {
+                SIPAUTHENTICATEHeader authHeader =
+                        new SIPAUTHENTICATEHeader(sipHeader.header, SIPStack.SIP_HEADERTYPE_PROXYAUTHENTICATE);
+                if (authHeader != null && authHeader.flag)
+                    if (authHeader.nonceValue.length() > 0 && authHeader.realmValue.length() > 0) {
+                        String qop = authHeader.qopValue;
+                        String uri = "sip:" + this.serverDomain + ":" + this.serverPort;
+                        this.authorizationH = getProxyAuthorizationHeader(
+                                qop,
+                                this.authid,
+                                authHeader.realmValue,
+                                this.authpassword, uri,
+                                authHeader.nonceValue,
+                                SIPStack.SIP_METHODTYPE_REGISTER);
+                        return true;
+                    }
+            }
+            return false;
+        } catch (Exception exception) {
+            return false;
+        }
+    }
+
+    public void action_reg_4(String message) {
+        try {
+            SIPHeader sipHeader = new SIPHeader(message, SIPStack.SIP_HEADERTYPE_MINEXPIRES);
+            if (sipHeader != null && sipHeader.flag)
+                this.expiresSeconds = Integer.parseInt(sipHeader.headerValue);
+            this.regState = SIPStack.SIP_REGSTATE_IDLE;
+        } catch (Exception exception) {}
+    }
+
+    public boolean action_bye_0(SIPCall sipCall, String message) {
+        try {
+            SIPRequestLine requestLine = new SIPRequestLine(message);
+            if (requestLine != null) {
+                SIPHeader sipHeader = new SIPHeader(message, SIPStack.SIP_HEADERTYPE_CALLID);
+                boolean bValidCall = false;
+                if (sipHeader != null && sipHeader.flag)
+                    if (sipHeader.headerValue != null &&
+                            sipHeader.headerValue.length() > 0 &&
+                            sipCall.callId != null &&
+                            sipHeader.headerValue.compareTo(sipCall.callId) == 0)
+                        bValidCall = true;
+                if (bValidCall) {
+                    sipHeader = new SIPHeader(message, SIPStack.SIP_HEADERTYPE_CSEQ);
+                    if (sipHeader != null && sipHeader.flag) {
+                        int duration = 0;
+                        Date currentTime = new Date();
+                        if (sipCall.callTime_T4 != null)
+                            duration = (int)(currentTime.getTime() - sipCall.callTime_T4.getTime()) / 1000;
+                        sipCall.BYE_CSEQ = sipHeader.callSequenceNumber();
+                        sipCall.callState = 9;
+                        sipCall.callTime_T6 = new Date();
+                        return true;
+                    }
+                }
+            }
+        } catch (Exception exception) {}
+        return false;
+    }
+
+    public boolean action_bye_1(SIPCall sipCall, String message) {
+        try {
+            SIPHeader sipHeader = new SIPHeader(message, SIPStack.SIP_HEADERTYPE_CALLID);
+            boolean bValidCall = false;
+            if (sipHeader != null && sipHeader.flag)
+                if (sipHeader.headerValue != null &&
+                        sipHeader.headerValue.length() > 0 &&
+                        sipCall.callId != null &&
+                        sipHeader.headerValue.compareTo(sipCall.callId) == 0)
+                    bValidCall = true;
+            if (bValidCall) {
+                sipHeader = new SIPHeader(message, SIPStack.SIP_HEADERTYPE_CSEQ);
+                if (sipHeader != null && sipHeader.flag) {
+                    sipCall.BYE_CSEQ = sipHeader.callSequenceNumber();
+                    sipCall.bByedisconnected = false;
+                    sipCall.resetCall();
+                    return true;
+                }
+            }
+        } catch (Exception exception) {}
+        return false;
+    }
+
+    public boolean action_info_0(SIPCall sipCall, String message, int msgType) {
+        try {
+            if (msgType == SIPStack.SIP_MSGTYPE_REQUEST &&
+                    sipCall.flag &&
+                    sipCall.callState == 7) {
+                SIPRequestLine requestLine = new SIPRequestLine(message);
+                if (requestLine != null) {
+                    SIPHeader sipHeader = new SIPHeader(message, SIPStack.SIP_HEADERTYPE_CALLID);
+                    if (sipHeader != null && sipHeader.flag)
+                        if (sipHeader.headerValue != null &&
+                                sipHeader.headerValue.length() > 0 &&
+                                sipCall.callId != null &&
+                                sipHeader.headerValue.compareTo(sipCall.callId) == 0)
+                            return true;
+                }
+            }
+        } catch (Exception exception) {}
+        return false;
+    }
+
+    public String getAuthorizationHeader(String qop, String authid, String realmValue, String authpassword, String uri, String nonceValue, int methodType) {
+        String strHeader = null;
+        String finalDigest = null;
+        String step1Digest = SIPStack.BSSMD5Get(String.valueOf(authid) + ":" + realmValue + ":" + authpassword);
+        String step2Digest = null;
+        if (methodType == SIPStack.SIP_METHODTYPE_REGISTER) {
+            step2Digest = SIPStack.BSSMD5Get("REGISTER:" + uri);
+        } else if (methodType == SIPStack.SIP_METHODTYPE_INVITE) {
+            step2Digest = SIPStack.BSSMD5Get("INVITE:" + uri);
+        } else if (methodType == SIPStack.SIP_METHODTYPE_CANCEL) {
+            step2Digest = SIPStack.BSSMD5Get("CANCEL:" + uri);
+        } else if (methodType == SIPStack.SIP_METHODTYPE_ACK) {
+            step2Digest = SIPStack.BSSMD5Get("ACK:" + uri);
+        } else if (methodType == SIPStack.SIP_METHODTYPE_BYE) {
+            step2Digest = SIPStack.BSSMD5Get("BYE:" + uri);
+        }
+        this.registerNonceCount++;
+        if (qop.length() > 0) {
+            int nonceCount = 0;
+            String cnonce = SIPStack.BSSMD5Get("60cf184b29500b20" + this.registerNonceCount);
+            if (nonceValue.length() > 0)
+                nonceCount = 1;
+            finalDigest = SIPStack.BSSMD5Get(String.valueOf(step1Digest) + ":" + nonceValue + ":" + String.format("%08x", new Object[] { Integer.valueOf(nonceCount) }) + ":" + cnonce + ":" + qop + ":" + step2Digest);
+            strHeader = "Authorization: Digest username=\"" +
+                    authid + "\"," +
+                    " realm=\"" + realmValue + "\"," +
+                    " nonce=\"" + nonceValue + "\"," +
+                    " uri=\"" + uri + "\"," +
+                    " response=\"" + finalDigest + "\"," +
+                    " cnonce=\"" + cnonce + "\"," +
+                    " nc=" + String.format("%08x", new Object[] { Integer.valueOf(nonceCount) }) + "," +
+                    " qop=" + qop + "," +
+                    " algorithm=MD5";
+        } else {
+            finalDigest = SIPStack.BSSMD5Get(String.valueOf(step1Digest) + ":" + nonceValue + ":" + step2Digest);
+            strHeader = "Authorization: Digest username=\"" +
+                    authid + "\"," +
+                    " realm=\"" + realmValue + "\"," +
+                    " nonce=\"" + nonceValue + "\"," +
+                    " uri=\"" + uri + "\"," +
+                    " response=\"" + finalDigest + "\"," +
+                    " algorithm=MD5";
+        }
+        return strHeader;
+    }
+
+    public String getProxyAuthorizationHeader(String qop, String authid, String realmValue, String authpassword, String uri, String nonceValue, int methodType) {
+        String strHeader = null;
+        String finalDigest = null;
+        String step1Digest = SIPStack.BSSMD5Get(String.valueOf(authid) + ":" + realmValue + ":" + authpassword);
+        String step2Digest = null;
+        if (methodType == SIPStack.SIP_METHODTYPE_REGISTER) {
+            step2Digest = SIPStack.BSSMD5Get("REGISTER:" + uri);
+        } else if (methodType == SIPStack.SIP_METHODTYPE_INVITE) {
+            step2Digest = SIPStack.BSSMD5Get("INVITE:" + uri);
+        } else if (methodType == SIPStack.SIP_METHODTYPE_CANCEL) {
+            step2Digest = SIPStack.BSSMD5Get("CANCEL:" + uri);
+        } else if (methodType == SIPStack.SIP_METHODTYPE_ACK) {
+            step2Digest = SIPStack.BSSMD5Get("ACK:" + uri);
+        } else if (methodType == SIPStack.SIP_METHODTYPE_BYE) {
+            step2Digest = SIPStack.BSSMD5Get("BYE:" + uri);
+        }
+        this.registerNonceCount++;
+        if (qop.length() > 0) {
+            int nonceCount = 0;
+            String cnonce = SIPStack.BSSMD5Get("60cf184b29500b20" + this.registerNonceCount);
+            if (nonceValue.length() > 0)
+                nonceCount = 1;
+            finalDigest = SIPStack.BSSMD5Get(String.valueOf(step1Digest) + ":" + nonceValue + ":" + String.format("%08x", new Object[] { Integer.valueOf(nonceCount) }) + ":" + cnonce + ":" + qop + ":" + step2Digest);
+            strHeader = "Proxy-Authorization: Digest username=\"" +
+                    authid + "\"," +
+                    " realm=\"" + realmValue + "\"," +
+                    " nonce=\"" + nonceValue + "\"," +
+                    " uri=\"" + uri + "\"," +
+                    " response=\"" + finalDigest + "\"," +
+                    " cnonce=\"" + cnonce + "\"," +
+                    " nc=" + String.format("%08x", new Object[] { Integer.valueOf(nonceCount) }) + "," +
+                    " qop=" + qop + "," +
+                    " algorithm=MD5";
+        } else {
+            finalDigest = SIPStack.BSSMD5Get(String.valueOf(step1Digest) + ":" + nonceValue + ":" + step2Digest);
+            strHeader = "Proxy-Authorization: Digest username=\"" +
+                    authid + "\"," +
+                    " realm=\"" + realmValue + "\"," +
+                    " nonce=\"" + nonceValue + "\"," +
+                    " uri=\"" + uri + "\"," +
+                    " response=\"" + finalDigest + "\"," +
+                    " algorithm=MD5";
+        }
+        return strHeader;
+    }
+
+    public boolean makeRegister() {
+        try {
+            this.CSEQ_NUMBER++;
+            this.commandLine = "REGISTER sip:" + this.serverDomain + ":" + this.serverPort + " SIP/2.0";
+            Date today = new Date();
+            this.viaH = "Via: SIP/2.0/UDP " + this.localIp + ":" + this.localPort + ";branch=" + SIPStack.getViaBranch() + ";rport";
+            this.maxforwardH = "Max-Forwards: 70";
+            if (this.ifIp != null && this.ifIp.length() > 0 && this.ifPort > 0) {
+                this.contactH = "Contact: <sip:" + this.id + "@" + this.ifIp + ":" + this.ifPort + ">";
+            } else {
+                this.contactH = "Contact: <sip:" + this.id + "@" + this.localIp + ":" + this.localPort + ">";
+            }
+            this.toH = "To: \"" + this.id + "\"<sip:" + this.id + "@" + this.serverDomain + ":" + this.serverPort + ">";
+            this.fromTag = SIPStack.newTag();
+            this.fromH = "From: \"" + this.id + "\"<sip:" + this.id + "@" + this.serverDomain + ":" + this.serverPort + ">;tag=" + this.fromTag;
+            if (this.callId == null || this.callId.length() == 0) {
+                this.callId = String.valueOf(SIPStack.BSSMD5Get(this.viaH)) + SIPStack.BSSMD5Get("1198602188") + today.getSeconds() + ".";
+                this.callidH = "Call-ID: " + this.callId;
+            }
+            if (this.CSEQ_NUMBER > 65556)
+                this.CSEQ_NUMBER = 0;
+            SIPStack.SIP_SEQUENCE_REGISTER = this.CSEQ_NUMBER;
+            this.cseqH = "CSeq: " + this.CSEQ_NUMBER + " REGISTER";
+            this.expiresH = "Expires: " + this.expiresSeconds;
+            this.allowH = "Allow: INVITE, ACK, CANCEL, OPTIONS, BYE, REFER, NOTIFY, MESSAGE, SUBSCRIBE, INFO";
+            this.useragentH = "User-Agent: KwangHaeSoft SmartSip release 0100o";
+            this.contentlengthH = "Content-Length: 0";
+            if (this.authorizationH != null && this.authorizationH.length() > 0) {
+                this.message = String.valueOf(this.commandLine) + SIPStack.SIP_LINE_END +
+                        this.viaH + SIPStack.SIP_LINE_END +
+                        this.maxforwardH + SIPStack.SIP_LINE_END +
+                        this.contactH + SIPStack.SIP_LINE_END +
+                        this.fromH + SIPStack.SIP_LINE_END +
+                        this.toH + SIPStack.SIP_LINE_END +
+                        this.callidH + SIPStack.SIP_LINE_END +
+                        this.cseqH + SIPStack.SIP_LINE_END +
+                        this.expiresH + SIPStack.SIP_LINE_END +
+                        this.allowH + SIPStack.SIP_LINE_END +
+                        this.useragentH + SIPStack.SIP_LINE_END +
+                        this.authorizationH + SIPStack.SIP_LINE_END +
+                        this.contentlengthH + SIPStack.SIP_LINE_DOUBLEEND;
+            } else {
+                this.message = String.valueOf(this.commandLine) + SIPStack.SIP_LINE_END +
+                        this.viaH + SIPStack.SIP_LINE_END +
+                        this.maxforwardH + SIPStack.SIP_LINE_END +
+                        this.contactH + SIPStack.SIP_LINE_END +
+                        this.fromH + SIPStack.SIP_LINE_END +
+                        this.toH + SIPStack.SIP_LINE_END +
+                        this.callidH + SIPStack.SIP_LINE_END +
+                        this.cseqH + SIPStack.SIP_LINE_END +
+                        this.expiresH + SIPStack.SIP_LINE_END +
+                        this.allowH + SIPStack.SIP_LINE_END +
+                        this.useragentH + SIPStack.SIP_LINE_END +
+                        this.contentlengthH + SIPStack.SIP_LINE_DOUBLEEND;
+            }
+            return true;
+        } catch (Exception exception) {
+            return false;
+        }
+    }
+
+    public boolean makeUNRegister() {
+        try {
+            this.CSEQ_NUMBER++;
+            this.commandLine = "REGISTER sip:" + this.serverDomain + ":" + this.serverPort + " SIP/2.0";
+            Date today = new Date();
+            this.viaH = "Via: SIP/2.0/UDP " + this.localIp + ":" + this.localPort + ";branch=" + SIPStack.getViaBranch() + ";rport";
+            this.maxforwardH = "Max-Forwards: 70";
+            if (this.ifIp != null && this.ifIp.length() > 0 && this.ifPort > 0) {
+                this.contactH = "Contact: <sip:" + this.id + "@" + this.ifIp + ":" + this.ifPort + ">;expires=0";
+            } else {
+                this.contactH = "Contact: <sip:" + this.id + "@" + this.localIp + ":" + this.localPort + ">;expires=0";
+            }
+            this.toH = "To: \"" + this.id + "\"<sip:" + this.id + "@" + this.serverDomain + ":" + this.serverPort + ">";
+            this.fromTag = SIPStack.newTag();
+            this.fromH = "From: \"" + this.id + "\"<sip:" + this.id + "@" + this.serverDomain + ":" + this.serverPort + ">;tag=" + this.fromTag;
+            if (this.callId == null || this.callId.length() == 0) {
+                this.callId = String.valueOf(SIPStack.BSSMD5Get(this.viaH)) + SIPStack.BSSMD5Get("1198602188") + today.getSeconds() + ".";
+                this.callidH = "Call-ID: " + this.callId;
+            }
+            if (this.CSEQ_NUMBER > 65556)
+                this.CSEQ_NUMBER = 0;
+            SIPStack.SIP_SEQUENCE_REGISTER = this.CSEQ_NUMBER;
+            this.cseqH = "CSeq: " + this.CSEQ_NUMBER + " REGISTER";
+            this.expiresH = "Expires: 0";
+            this.allowH = "Allow: INVITE, ACK, CANCEL, OPTIONS, BYE, REFER, NOTIFY, MESSAGE, SUBSCRIBE, INFO";
+            this.useragentH = "User-Agent: KwangHaeSoft SmartSip release 0100o";
+            this.contentlengthH = "Content-Length: 0";
+            if (this.authorizationH != null && this.authorizationH.length() > 0) {
+                this.message = String.valueOf(this.commandLine) + SIPStack.SIP_LINE_END +
+                        this.viaH + SIPStack.SIP_LINE_END +
+                        this.maxforwardH + SIPStack.SIP_LINE_END +
+                        this.contactH + SIPStack.SIP_LINE_END +
+                        this.fromH + SIPStack.SIP_LINE_END +
+                        this.toH + SIPStack.SIP_LINE_END +
+                        this.callidH + SIPStack.SIP_LINE_END +
+                        this.cseqH + SIPStack.SIP_LINE_END +
+                        this.expiresH + SIPStack.SIP_LINE_END +
+                        this.allowH + SIPStack.SIP_LINE_END +
+                        this.useragentH + SIPStack.SIP_LINE_END +
+                        this.authorizationH + SIPStack.SIP_LINE_END +
+                        this.contentlengthH + SIPStack.SIP_LINE_DOUBLEEND;
+            } else {
+                this.message = String.valueOf(this.commandLine) + SIPStack.SIP_LINE_END +
+                        this.viaH + SIPStack.SIP_LINE_END +
+                        this.maxforwardH + SIPStack.SIP_LINE_END +
+                        this.contactH + SIPStack.SIP_LINE_END +
+                        this.fromH + SIPStack.SIP_LINE_END +
+                        this.toH + SIPStack.SIP_LINE_END +
+                        this.callidH + SIPStack.SIP_LINE_END +
+                        this.cseqH + SIPStack.SIP_LINE_END +
+                        this.expiresH + SIPStack.SIP_LINE_END +
+                        this.allowH + SIPStack.SIP_LINE_END +
+                        this.useragentH + SIPStack.SIP_LINE_END +
+                        this.contentlengthH + SIPStack.SIP_LINE_DOUBLEEND;
+            }
+            return true;
+        } catch (Exception exception) {
+            return false;
+        }
+    }
+
+    public boolean makeUNRegister(String contactip, int contactport) {
+        try {
+            this.CSEQ_NUMBER++;
+            this.commandLine = "REGISTER sip:" + this.serverDomain + ":" + this.serverPort + " SIP/2.0";
+            Date today = new Date();
+            this.viaH = "Via: SIP/2.0/UDP " + this.localIp + ":" + this.localPort + ";branch=" + SIPStack.getViaBranch() + ";rport";
+            this.maxforwardH = "Max-Forwards: 70";
+            if (contactip != null && contactip.length() > 0 && contactport > 0) {
+                this.contactH = "Contact: <sip:" + this.id + "@" + contactip + ":" + contactport + ">";
+            } else {
+                return true;
+            }
+            this.toH = "To: \"" + this.id + "\"<sip:" + this.id + "@" + this.serverDomain + ":" + this.serverPort + ">";
+            this.fromTag = SIPStack.newTag();
+            this.fromH = "From: \"" + this.id + "\"<sip:" + this.id + "@" + this.serverDomain + ":" + this.serverPort + ">;tag=" + this.fromTag;
+            if (this.callId == null || this.callId.length() == 0) {
+                this.callId = String.valueOf(SIPStack.BSSMD5Get(this.viaH)) + SIPStack.BSSMD5Get("1198602188") + today.getSeconds() + ".";
+                this.callidH = "Call-ID: " + this.callId;
+            }
+            if (this.CSEQ_NUMBER > 65556)
+                this.CSEQ_NUMBER = 0;
+            SIPStack.SIP_SEQUENCE_REGISTER = this.CSEQ_NUMBER;
+            this.cseqH = "CSeq: " + this.CSEQ_NUMBER + " REGISTER";
+            this.expiresH = "Expires: 0";
+            this.allowH = "Allow: INVITE, ACK, CANCEL, OPTIONS, BYE, REFER, NOTIFY, MESSAGE, SUBSCRIBE, INFO";
+            this.useragentH = "User-Agent: KwangHaeSoft SmartSip release 0100o";
+            this.contentlengthH = "Content-Length: 0";
+            if (this.authorizationH != null && this.authorizationH.length() > 0) {
+                this.message = String.valueOf(this.commandLine) + SIPStack.SIP_LINE_END +
+                        this.viaH + SIPStack.SIP_LINE_END +
+                        this.maxforwardH + SIPStack.SIP_LINE_END +
+                        this.contactH + SIPStack.SIP_LINE_END +
+                        this.fromH + SIPStack.SIP_LINE_END +
+                        this.toH + SIPStack.SIP_LINE_END +
+                        this.callidH + SIPStack.SIP_LINE_END +
+                        this.cseqH + SIPStack.SIP_LINE_END +
+                        this.expiresH + SIPStack.SIP_LINE_END +
+                        this.allowH + SIPStack.SIP_LINE_END +
+                        this.useragentH + SIPStack.SIP_LINE_END +
+                        this.authorizationH + SIPStack.SIP_LINE_END +
+                        this.contentlengthH + SIPStack.SIP_LINE_DOUBLEEND;
+            } else {
+                this.message = String.valueOf(this.commandLine) + SIPStack.SIP_LINE_END +
+                        this.viaH + SIPStack.SIP_LINE_END +
+                        this.maxforwardH + SIPStack.SIP_LINE_END +
+                        this.contactH + SIPStack.SIP_LINE_END +
+                        this.fromH + SIPStack.SIP_LINE_END +
+                        this.toH + SIPStack.SIP_LINE_END +
+                        this.callidH + SIPStack.SIP_LINE_END +
+                        this.cseqH + SIPStack.SIP_LINE_END +
+                        this.expiresH + SIPStack.SIP_LINE_END +
+                        this.allowH + SIPStack.SIP_LINE_END +
+                        this.useragentH + SIPStack.SIP_LINE_END +
+                        this.contentlengthH + SIPStack.SIP_LINE_DOUBLEEND;
+            }
+            return true;
+        } catch (Exception exception) {
+            return false;
+        }
+    }
+
+    public boolean makeCancel(SIPCall sipCall) {
+        if (sipCall == null || !sipCall.flag)
+            return false;
+        sipCall.CANCEL_CSEQ = sipCall.CSEQ_NUMBER;
+        if (sipCall.callState != 1 &&
+                sipCall.callState != 3 &&
+                sipCall.callState != 4)
+            return false;
+        String commandLine = "CANCEL sip:" + sipCall.dnis + "@" + this.serverDomain + ":" + this.serverPort + " SIP/2.0";
+        String toH = "To: \"" + sipCall.dnis + "\"<sip:" + sipCall.dnis + "@" + sipCall.serverDomain + ":" + sipCall.serverPort + ">";
+        if (sipCall.viaH == null || sipCall.viaH.length() == 0) {
+            if (sipCall.viaBranch == null || sipCall.viaBranch.length() == 0)
+                sipCall.viaBranch = SIPStack.getViaBranch();
+            sipCall.viaH = "Via: SIP/2.0/UDP " + this.localIp + ":" + this.localPort + ";branch=" + sipCall.viaBranch + ";rport";
+        }
+        sipCall.cseqH = "CSeq: " + sipCall.CANCEL_CSEQ + " CANCEL";
+        sipCall.contentlengthH = "Content-Length: 0";
+        String routeString = "";
+        if (sipCall.routeArray != null &&
+                sipCall.routeArray.length() > 0)
+            routeString = sipCall.routeArray.toString();
+        if (this.ifIp != null && this.ifIp.length() > 0 && this.ifPort > 0) {
+            sipCall.contactH = "Contact: <sip:" + this.id + "@" + this.ifIp + ":" + this.ifPort + ">";
+        } else {
+            sipCall.contactH = "Contact: <sip:" + this.id + "@" + sipCall.localIp + ":" + sipCall.localPort + ">";
+        }
+        if (sipCall.authorizationCANCELH != null && sipCall.authorizationCANCELH.length() > 0) {
+            sipCall.message =
+                    String.valueOf(commandLine) + SIPStack.SIP_LINE_END +
+                            sipCall.viaH + SIPStack.SIP_LINE_END +
+                            routeString +
+                            sipCall.maxforwardH + SIPStack.SIP_LINE_END +
+                            sipCall.contactH + SIPStack.SIP_LINE_END +
+                            sipCall.fromH + SIPStack.SIP_LINE_END +
+                            toH + SIPStack.SIP_LINE_END +
+                            sipCall.callidH + SIPStack.SIP_LINE_END +
+                            sipCall.cseqH + SIPStack.SIP_LINE_END +
+                            sipCall.allowH + SIPStack.SIP_LINE_END +
+                            sipCall.useragentH + SIPStack.SIP_LINE_END +
+                            sipCall.authorizationCANCELH + SIPStack.SIP_LINE_END +
+                            sipCall.contentlengthH + SIPStack.SIP_LINE_DOUBLEEND;
+        } else {
+            sipCall.message =
+                    String.valueOf(commandLine) + SIPStack.SIP_LINE_END +
+                            sipCall.viaH + SIPStack.SIP_LINE_END +
+                            routeString +
+                            sipCall.maxforwardH + SIPStack.SIP_LINE_END +
+                            sipCall.contactH + SIPStack.SIP_LINE_END +
+                            sipCall.fromH + SIPStack.SIP_LINE_END +
+                            toH + SIPStack.SIP_LINE_END +
+                            sipCall.callidH + SIPStack.SIP_LINE_END +
+                            sipCall.cseqH + SIPStack.SIP_LINE_END +
+                            sipCall.allowH + SIPStack.SIP_LINE_END +
+                            sipCall.useragentH + SIPStack.SIP_LINE_END +
+                            sipCall.contentlengthH + SIPStack.SIP_LINE_DOUBLEEND;
+        }
+        return true;
+    }
+
+    public boolean makeRecancel(SIPCall sipCall) {
+        if (sipCall == null || !sipCall.flag)
+            return false;
+        sipCall.CANCEL_CSEQ = sipCall.CSEQ_NUMBER;
+        if (sipCall.callState != 11)
+            return false;
+        String commandLine = "CANCEL sip:" + sipCall.dnis + "@" + this.serverDomain + ":" + this.serverPort + " SIP/2.0";
+        String toH = "To: \"" + sipCall.dnis + "\"<sip:" + sipCall.dnis + "@" + sipCall.serverDomain + ":" + sipCall.serverPort + ">";
+        if (sipCall.viaH == null || sipCall.viaH.length() == 0) {
+            if (sipCall.viaBranch == null || sipCall.viaBranch.length() == 0)
+                sipCall.viaBranch = SIPStack.getViaBranch();
+            sipCall.viaH = "Via: SIP/2.0/UDP " + this.localIp + ":" + this.localPort + ";branch=" + sipCall.viaBranch + ";rport";
+        }
+        sipCall.cseqH = "CSeq: " + sipCall.CANCEL_CSEQ + " CANCEL";
+        sipCall.contentlengthH = "Content-Length: 0";
+        String routeString = "";
+        if (sipCall.routeArray != null &&
+                sipCall.routeArray.length() > 0)
+            routeString = sipCall.routeArray.toString();
+        if (this.ifIp != null && this.ifIp.length() > 0 && this.ifPort > 0) {
+            sipCall.contactH = "Contact: <sip:" + this.id + "@" + this.ifIp + ":" + this.ifPort + ">";
+        } else {
+            sipCall.contactH = "Contact: <sip:" + this.id + "@" + sipCall.localIp + ":" + sipCall.localPort + ">";
+        }
+        if (sipCall.authorizationCANCELH != null && sipCall.authorizationCANCELH.length() > 0) {
+            sipCall.message =
+                    String.valueOf(commandLine) + SIPStack.SIP_LINE_END +
+                            sipCall.viaH + SIPStack.SIP_LINE_END +
+                            routeString +
+                            sipCall.maxforwardH + SIPStack.SIP_LINE_END +
+                            sipCall.contactH + SIPStack.SIP_LINE_END +
+                            sipCall.fromH + SIPStack.SIP_LINE_END +
+                            toH + SIPStack.SIP_LINE_END +
+                            sipCall.callidH + SIPStack.SIP_LINE_END +
+                            sipCall.cseqH + SIPStack.SIP_LINE_END +
+                            sipCall.allowH + SIPStack.SIP_LINE_END +
+                            sipCall.useragentH + SIPStack.SIP_LINE_END +
+                            sipCall.authorizationCANCELH + SIPStack.SIP_LINE_END +
+                            sipCall.contentlengthH + SIPStack.SIP_LINE_DOUBLEEND;
+        } else {
+            sipCall.message =
+                    String.valueOf(commandLine) + SIPStack.SIP_LINE_END +
+                            sipCall.viaH + SIPStack.SIP_LINE_END +
+                            routeString +
+                            sipCall.maxforwardH + SIPStack.SIP_LINE_END +
+                            sipCall.contactH + SIPStack.SIP_LINE_END +
+                            sipCall.fromH + SIPStack.SIP_LINE_END +
+                            toH + SIPStack.SIP_LINE_END +
+                            sipCall.callidH + SIPStack.SIP_LINE_END +
+                            sipCall.cseqH + SIPStack.SIP_LINE_END +
+                            sipCall.allowH + SIPStack.SIP_LINE_END +
+                            sipCall.useragentH + SIPStack.SIP_LINE_END +
+                            sipCall.contentlengthH + SIPStack.SIP_LINE_DOUBLEEND;
+        }
+        return true;
+    }
+
+    public boolean makeBye(SIPCall sipCall) {
+        if (sipCall == null || !sipCall.flag)
+            return false;
+        if (sipCall.callState != 7 &&
+                sipCall.callState != 5 &&
+                sipCall.callState != 6)
+            return false;
+        String commandLine = null;
+        if (sipCall.remoteContactUri != null && sipCall.remoteContactUri.length() > 0) {
+            commandLine = "BYE " + sipCall.remoteContactUri + " SIP/2.0";
+        } else {
+            commandLine = "BYE sip:" + sipCall.dnis + "@" + this.serverDomain + ":" + this.serverPort + " SIP/2.0";
+        }
+        if (sipCall.viaBranch == null || sipCall.viaBranch.length() == 0)
+            sipCall.viaBranch = SIPStack.getViaBranch();
+        String viaH = "Via: SIP/2.0/UDP " + this.localIp + ":" + this.localPort + ";branch=" + sipCall.viaBranch;
+        String maxforwardH = "Max-Forwards: 70";
+        String contactH = null;
+        if (this.ifIp != null && this.ifIp.length() > 0 && this.ifPort > 0) {
+            contactH = "Contact: <sip:" + this.id + "@" + this.ifIp + ":" + this.ifPort + ">";
+        } else {
+            contactH = "Contact: <sip:" + this.id + "@" + sipCall.localIp + ":" + sipCall.localPort + ">";
+        }
+        String toH = null;
+        if (sipCall.callDirection == SIPStack.SIP_CALLDIRECTION_IN) {
+            if (sipCall.fromHeaderValue == null || sipCall.fromHeaderValue.length() == 0) {
+                toH = "To: \"" + sipCall.dnis + "\"<sip:" + sipCall.dnis + "@" + sipCall.serverDomain + ":" + sipCall.serverPort + ">;tag=" + sipCall.fromTag;
+            } else {
+                toH = "To: " + sipCall.fromHeaderValue;
+            }
+        } else {
+            toH = "To: \"" + sipCall.dnis + "\"<sip:" + sipCall.dnis + "@" + sipCall.serverDomain + ":" + sipCall.serverPort + ">;tag=" + sipCall.toTag;
+        }
+        String fromH = null;
+        if (sipCall.callDirection == SIPStack.SIP_CALLDIRECTION_IN) {
+            if (sipCall.toHeaderValue == null || sipCall.toHeaderValue.length() == 0) {
+                fromH = "From: \"" + sipCall.id + "\"<sip:" + sipCall.id + "@" + sipCall.serverDomain + ":" + sipCall.serverPort + ">;tag=" + sipCall.toTag;
+            } else {
+                fromH = "From: " + sipCall.toHeaderValue;
+            }
+        } else {
+            fromH = "From: \"" + sipCall.id + "\"<sip:" + sipCall.id + "@" + sipCall.serverDomain + ":" + sipCall.serverPort + ">;tag=" + sipCall.fromTag;
+        }
+        sipCall.BYE_CSEQ = sipCall.CSEQ_NUMBER + 1;
+        String cseqH = "CSeq: " + sipCall.BYE_CSEQ + " BYE";
+        String contentlengthH = "Content-Length: 0";
+        String routeString = "";
+        if (sipCall.routeArray != null &&
+                sipCall.routeArray.length() > 0)
+            routeString = sipCall.routeArray.toString();
+        if (sipCall.authorizationBYEH != null && sipCall.authorizationBYEH.length() > 0) {
+            sipCall.message =
+                    String.valueOf(commandLine) + SIPStack.SIP_LINE_END +
+                            viaH + SIPStack.SIP_LINE_END +
+                            routeString +
+                            maxforwardH + SIPStack.SIP_LINE_END +
+                            contactH + SIPStack.SIP_LINE_END +
+                            fromH + SIPStack.SIP_LINE_END +
+                            toH + SIPStack.SIP_LINE_END +
+                            sipCall.callidH + SIPStack.SIP_LINE_END +
+                            cseqH + SIPStack.SIP_LINE_END +
+                            sipCall.allowH + SIPStack.SIP_LINE_END +
+                            sipCall.useragentH + SIPStack.SIP_LINE_END +
+                            sipCall.authorizationBYEH + SIPStack.SIP_LINE_END +
+                            contentlengthH + SIPStack.SIP_LINE_DOUBLEEND;
+        } else {
+            sipCall.message =
+                    String.valueOf(commandLine) + SIPStack.SIP_LINE_END +
+                            viaH + SIPStack.SIP_LINE_END +
+                            routeString +
+                            maxforwardH + SIPStack.SIP_LINE_END +
+                            contactH + SIPStack.SIP_LINE_END +
+                            fromH + SIPStack.SIP_LINE_END +
+                            toH + SIPStack.SIP_LINE_END +
+                            sipCall.callidH + SIPStack.SIP_LINE_END +
+                            cseqH + SIPStack.SIP_LINE_END +
+                            sipCall.allowH + SIPStack.SIP_LINE_END +
+                            sipCall.useragentH + SIPStack.SIP_LINE_END +
+                            contentlengthH + SIPStack.SIP_LINE_DOUBLEEND;
+        }
+        return true;
+    }
+
+    public boolean makeReBye(SIPCall sipCall) {
+        if (sipCall == null || !sipCall.flag)
+            return false;
+        if (sipCall.callState != 8 ||
+                !sipCall.bByedisconnected)
+            return false;
+        String commandLine = null;
+        if (sipCall.remoteContactUri != null && sipCall.remoteContactUri.length() > 0) {
+            commandLine = "BYE " + sipCall.remoteContactUri + " SIP/2.0";
+        } else {
+            commandLine = "BYE sip:" + sipCall.dnis + "@" + this.serverDomain + ":" + this.serverPort + " SIP/2.0";
+        }
+        if (sipCall.viaBranch == null || sipCall.viaBranch.length() == 0)
+            sipCall.viaBranch = SIPStack.getViaBranch();
+        String viaH = "Via: SIP/2.0/UDP " + this.localIp + ":" + this.localPort + ";branch=" + sipCall.viaBranch;
+        String maxforwardH = "Max-Forwards: 70";
+        String contactH = null;
+        if (this.ifIp != null && this.ifIp.length() > 0 && this.ifPort > 0) {
+            contactH = "Contact: <sip:" + this.id + "@" + this.ifIp + ":" + this.ifPort + ">";
+        } else {
+            contactH = "Contact: <sip:" + this.id + "@" + sipCall.localIp + ":" + sipCall.localPort + ">";
+        }
+        String toH = null;
+        if (sipCall.callDirection == SIPStack.SIP_CALLDIRECTION_IN) {
+            if (sipCall.fromHeaderValue == null || sipCall.fromHeaderValue.length() == 0) {
+                toH = "To: \"" + sipCall.dnis + "\"<sip:" + sipCall.dnis + "@" + sipCall.serverDomain + ":" + sipCall.serverPort + ">;tag=" + sipCall.fromTag;
+            } else {
+                toH = "To: " + sipCall.fromHeaderValue;
+            }
+        } else {
+            toH = "To: \"" + sipCall.dnis + "\"<sip:" + sipCall.dnis + "@" + sipCall.serverDomain + ":" + sipCall.serverPort + ">;tag=" + sipCall.toTag;
+        }
+        String fromH = null;
+        if (sipCall.callDirection == SIPStack.SIP_CALLDIRECTION_IN) {
+            if (sipCall.toHeaderValue == null || sipCall.toHeaderValue.length() == 0) {
+                fromH = "From: \"" + sipCall.id + "\"<sip:" + sipCall.id + "@" + sipCall.serverDomain + ":" + sipCall.serverPort + ">;tag=" + sipCall.toTag;
+            } else {
+                fromH = "From: " + sipCall.toHeaderValue;
+            }
+        } else {
+            fromH = "From: \"" + sipCall.id + "\"<sip:" + sipCall.id + "@" + sipCall.serverDomain + ":" + sipCall.serverPort + ">;tag=" + sipCall.fromTag;
+        }
+        sipCall.BYE_CSEQ = sipCall.CSEQ_NUMBER + 1;
+        String cseqH = "CSeq: " + sipCall.BYE_CSEQ + " BYE";
+        String contentlengthH = "Content-Length: 0";
+        String routeString = "";
+        if (sipCall.routeArray != null &&
+                sipCall.routeArray.length() > 0)
+            routeString = sipCall.routeArray.toString();
+        if (sipCall.authorizationBYEH != null && sipCall.authorizationBYEH.length() > 0) {
+            sipCall.message =
+                    String.valueOf(commandLine) + SIPStack.SIP_LINE_END +
+                            viaH + SIPStack.SIP_LINE_END +
+                            routeString +
+                            maxforwardH + SIPStack.SIP_LINE_END +
+                            contactH + SIPStack.SIP_LINE_END +
+                            fromH + SIPStack.SIP_LINE_END +
+                            toH + SIPStack.SIP_LINE_END +
+                            sipCall.callidH + SIPStack.SIP_LINE_END +
+                            cseqH + SIPStack.SIP_LINE_END +
+                            sipCall.allowH + SIPStack.SIP_LINE_END +
+                            sipCall.useragentH + SIPStack.SIP_LINE_END +
+                            sipCall.authorizationBYEH + SIPStack.SIP_LINE_END +
+                            contentlengthH + SIPStack.SIP_LINE_DOUBLEEND;
+        } else {
+            sipCall.message =
+                    String.valueOf(commandLine) + SIPStack.SIP_LINE_END +
+                            viaH + SIPStack.SIP_LINE_END +
+                            routeString +
+                            maxforwardH + SIPStack.SIP_LINE_END +
+                            contactH + SIPStack.SIP_LINE_END +
+                            fromH + SIPStack.SIP_LINE_END +
+                            toH + SIPStack.SIP_LINE_END +
+                            sipCall.callidH + SIPStack.SIP_LINE_END +
+                            cseqH + SIPStack.SIP_LINE_END +
+                            sipCall.allowH + SIPStack.SIP_LINE_END +
+                            sipCall.useragentH + SIPStack.SIP_LINE_END +
+                            contentlengthH + SIPStack.SIP_LINE_DOUBLEEND;
+        }
+        return true;
+    }
+
+    public String getVideomediadescription(int port) {
+        String str = "m=video " + port + " RTP/AVP " + SIPStack.SIP_CODEC_H263 + SIPStack.SIP_LINE_END +
+                "a=rtpmap:" + SIPStack.SIP_CODEC_H263 + " H263/90000" + SIPStack.SIP_LINE_END +
+                "a=fmtp:" + SIPStack.SIP_CODEC_H263 + " packetization-mode=1;profile-level-id=2" + SIPStack.SIP_LINE_END +
+                "a=cliprect:0,0,288,352" + SIPStack.SIP_LINE_END +
+                "a=framesize:" + SIPStack.SIP_CODEC_H263 + " 352-288" + SIPStack.SIP_LINE_END;
+        //String str = "";
+        return str;
+    }
+
+    public boolean makeDirectcallMake(SIPCall sipCall, String number) {
+        String header = "";
+        if (sipCall == null || sipCall.flag)
+            return false;
+        sipCall.CSEQ_NUMBER = SIPStack.SIP_SEQUENCE_INVITE;
+        SIPStack.SIP_SEQUENCE_INVITE++;
+        if (SIPStack.SIP_SEQUENCE_INVITE > 65556)
+            SIPStack.SIP_SEQUENCE_INVITE = 1;
+        if (!sipCall.activeCallHandle(
+                this.id,
+                this.cid,
+                this.authid,
+                this.authpassword,
+                number,
+                sipCall.serverIp,
+                sipCall.serverPort,
+                sipCall.serverDomain,
+                this.localIp,
+                this.localPort))
+            return false;
+        if (number.length() <= 0)
+            return false;
+        sipCall.commandLine = "INVITE sip:" + number + "@" + sipCall.serverDomain + ":" + sipCall.serverPort + " SIP/2.0";
+        Date today = new Date();
+        sipCall.viaBranch = SIPStack.getViaBranch();
+        sipCall.viaH = "Via: SIP/2.0/UDP " + this.localIp + ":" + this.localPort + ";branch=" + sipCall.viaBranch + ";rport";
+        sipCall.maxforwardH = "Max-Forwards: 70";
+        if (this.ifIp != null && this.ifIp.length() > 0 && this.ifPort > 0) {
+            sipCall.contactH = "Contact: <sip:" + this.id + "@" + this.ifIp + ":" + this.ifPort + ">";
+        } else {
+            sipCall.contactH = "Contact: <sip:" + this.id + "@" + sipCall.localIp + ":" + sipCall.localPort + ">";
+        }
+        sipCall.toH = "To: \"" + number + "\"<sip:" + number + "@" + sipCall.serverDomain + ":" + sipCall.serverPort + ">";
+        sipCall.fromTag = SIPStack.newTag();
+        sipCall.fromH = "From: \"" + sipCall.id + "\"<sip:" + sipCall.id + "@" + sipCall.serverDomain + ":" + sipCall.serverPort + ">;tag=" + sipCall.fromTag;
+        if (BSSVideo.HNS_SERVICE_ORIGINATOR_SELECTED == BSSVideo.HNS_SERVICE_LOBBY) {
+            String postFix = "";
+            if (BSSVideo.HNS_SERVICE_RECEIVER_SELECTED == BSSVideo.HNS_SERVICE_GUARD) {
+                postFix = BSSVideo.HNS_POSTFIX_GUARD;
+                sipCall.hnsReceiverServiceType = BSSVideo.HNS_SERVICE_GUARD;
+            } else if (BSSVideo.HNS_SERVICE_RECEIVER_SELECTED == BSSVideo.HNS_SERVICE_NEIGHBOR) {
+                postFix = BSSVideo.HNS_POSTFIX_NEIGHBOR;
+                sipCall.hnsReceiverServiceType = BSSVideo.HNS_SERVICE_NEIGHBOR;
+            } else {
+                postFix = BSSVideo.HNS_POSTFIX_LOBBY;
+                sipCall.hnsReceiverServiceType = BSSVideo.HNS_SERVICE_ORIGINATOR_SELECTED;
+            }
+            sipCall.callId = String.valueOf(BSSVideo.HNS_PREFIX_LOBBY) + SIPStack.BSSMD5Get(this.viaH) +
+                    SIPStack.BSSMD5Get("1198602188") + today.getSeconds() + "." + postFix;
+            sipCall.hnsOriginatorServiceType = BSSVideo.HNS_SERVICE_LOBBY;
+            BSSVideo.bProgressvideooffer = true;
+        } else if (BSSVideo.HNS_SERVICE_ORIGINATOR_SELECTED == BSSVideo.HNS_SERVICE_GUARD) {
+            String postFix = "";
+            if (BSSVideo.HNS_SERVICE_RECEIVER_SELECTED == BSSVideo.HNS_SERVICE_GUARD) {
+                postFix = BSSVideo.HNS_POSTFIX_GUARD;
+                sipCall.hnsReceiverServiceType = BSSVideo.HNS_SERVICE_GUARD;
+            } else if (BSSVideo.HNS_SERVICE_RECEIVER_SELECTED == BSSVideo.HNS_SERVICE_NEIGHBOR) {
+                postFix = BSSVideo.HNS_POSTFIX_NEIGHBOR;
+                sipCall.hnsReceiverServiceType = BSSVideo.HNS_SERVICE_NEIGHBOR;
+            } else {
+                postFix = BSSVideo.HNS_POSTFIX_GUARD;
+                sipCall.hnsReceiverServiceType = BSSVideo.HNS_SERVICE_ORIGINATOR_SELECTED;
+            }
+            sipCall.callId = String.valueOf(BSSVideo.HNS_PREFIX_GUARD) + SIPStack.BSSMD5Get(this.viaH) +
+                    SIPStack.BSSMD5Get("1198602188") + today.getSeconds() + "." + postFix;
+            sipCall.hnsOriginatorServiceType = BSSVideo.HNS_SERVICE_GUARD;
+            BSSVideo.bProgressvideooffer = true;
+        } else if (BSSVideo.HNS_SERVICE_ORIGINATOR_SELECTED == BSSVideo.HNS_SERVICE_NEIGHBOR) {
+            String postFix = "";
+            if (BSSVideo.HNS_SERVICE_RECEIVER_SELECTED == BSSVideo.HNS_SERVICE_GUARD) {
+                postFix = BSSVideo.HNS_POSTFIX_GUARD;
+                sipCall.hnsReceiverServiceType = BSSVideo.HNS_SERVICE_GUARD;
+                BSSVideo.bProgressvideooffer = true;
+            } else if (BSSVideo.HNS_SERVICE_RECEIVER_SELECTED == BSSVideo.HNS_SERVICE_NEIGHBOR) {
+                postFix = BSSVideo.HNS_POSTFIX_NEIGHBOR;
+                sipCall.hnsReceiverServiceType = BSSVideo.HNS_SERVICE_NEIGHBOR;
+                BSSVideo.bProgressvideooffer = true;
+            } else {
+                postFix = BSSVideo.HNS_POSTFIX_NEIGHBOR;
+                sipCall.hnsReceiverServiceType = BSSVideo.HNS_SERVICE_ORIGINATOR_SELECTED;
+                BSSVideo.bProgressvideooffer = false;
+            }
+            sipCall.callId = String.valueOf(BSSVideo.HNS_PREFIX_NEIGHBOR) + SIPStack.BSSMD5Get(this.viaH) +
+                    SIPStack.BSSMD5Get("1198602188") + today.getSeconds() + "." + postFix;
+            sipCall.hnsOriginatorServiceType = BSSVideo.HNS_SERVICE_NEIGHBOR;
+        } else {
+            sipCall.callId = String.valueOf(SIPStack.BSSMD5Get(this.viaH)) + SIPStack.BSSMD5Get("1198602188") + today.getSeconds() + ".";
+            sipCall.hnsOriginatorServiceType = BSSVideo.HNS_SERVICE_NONE;
+            sipCall.hnsReceiverServiceType = BSSVideo.HNS_SERVICE_NONE;
+            BSSVideo.bProgressvideooffer = false;
+        }
+        sipCall.callidH = "Call-ID: " + sipCall.callId;
+        sipCall.cseqH = "CSeq: " + sipCall.CSEQ_NUMBER + " INVITE";
+        sipCall.allowH = "Allow: INVITE, ACK, CANCEL, OPTIONS, BYE, REFER, NOTIFY, MESSAGE, SUBSCRIBE, INFO";
+        sipCall.useragentH = "User-Agent: KwangHaeSoft SmartSip release 0100o";
+        if (sipCall.cid != null && sipCall.cid.length() > 0) {
+            sipCall.passertedidentityH = "P-Asserted-Identity: <sip:" + sipCall.cid + "@" + sipCall.localIp + ":" + sipCall.localPort + ">";
+            header = "P-Asserted-Identity: <sip:" + sipCall.cid + "@" + sipCall.localIp + ":" + sipCall.localPort + ">" + SIPStack.SIP_LINE_END;
+        } else {
+            sipCall.passertedidentityH = null;
+            header = "";
+        }
+        int audioport = SIPStack.getFreeAudioRtpPort();
+        if (audioport > 0)
+            sipCall.constructSdp();
+        if (sipCall.sdp != null && sipCall.sdp.flag) {
+            sipCall.sdp.setMediaPort(SIPStack.SIP_MEDIATYPE_AUDIO, audioport);
+            if (SIPStack.PRIMARY_CODEC_AUDIO == SIPStack.SIP_CODEC_G711U) {
+                sipCall.sdp.setCodec(
+                        SIPStack.SIP_MEDIATYPE_AUDIO,
+                        SIPStack.SIP_CODEC_G711U,
+                        "PCMU/8000");
+                sipCall.sdp.setCodec(
+                        SIPStack.SIP_MEDIATYPE_AUDIO,
+                        SIPStack.SIP_CODEC_G711A,
+                        "PCMA/8000");
+            } else {
+                sipCall.sdp.setCodec(
+                        SIPStack.SIP_MEDIATYPE_AUDIO,
+                        SIPStack.SIP_CODEC_G711A,
+                        "PCMA/8000");
+                sipCall.sdp.setCodec(
+                        SIPStack.SIP_MEDIATYPE_AUDIO,
+                        SIPStack.SIP_CODEC_G711U,
+                        "PCMU/8000");
+            }
+            sipCall.sdp.setCodec(
+                    SIPStack.SIP_MEDIATYPE_AUDIO,
+                    RFC2833.payloadType,
+                    "telephone-event/8000");
+            sipCall.sdp.setFmtpDescribe(SIPStack.SIP_MEDIATYPE_AUDIO, RFC2833.payloadType, "0-15");
+        }
+        String body = null;
+        sipCall.contenttypeH = "";
+        if (sipCall.sdp != null && sipCall.sdp.flag) {
+            sipCall.contenttypeH = "Content-Type: application/SDP\r\n";
+            if (SIPStack.bVideocommunication) {
+                body = String.valueOf(sipCall.sdp.getBodyString()) + getVideomediadescription(audioport + 2);
+            } else {
+                body = sipCall.sdp.getBodyString();
+            }
+            sipCall.contentlengthH = "Content-Length: " + body.length();
+        } else {
+            body = "";
+            sipCall.contentlengthH = "Content-Length: 0";
+        }
+        sipCall.callState = 1;
+        sipCall.callDirection = SIPStack.SIP_CALLDIRECTION_OUT;
+        if (sipCall.authorizationINVITEH != null && sipCall.authorizationINVITEH.length() > 0) {
+            sipCall.message =
+                    String.valueOf(sipCall.commandLine) + SIPStack.SIP_LINE_END +
+                            sipCall.viaH + SIPStack.SIP_LINE_END +
+                            sipCall.maxforwardH + SIPStack.SIP_LINE_END +
+                            sipCall.contactH + SIPStack.SIP_LINE_END +
+                            sipCall.fromH + SIPStack.SIP_LINE_END +
+                            sipCall.toH + SIPStack.SIP_LINE_END +
+                            sipCall.callidH + SIPStack.SIP_LINE_END +
+                            sipCall.cseqH + SIPStack.SIP_LINE_END +
+                            sipCall.allowH + SIPStack.SIP_LINE_END +
+                            sipCall.useragentH + SIPStack.SIP_LINE_END +
+                            header +
+                            sipCall.authorizationINVITEH + SIPStack.SIP_LINE_END +
+                            sipCall.contenttypeH +
+                            sipCall.contentlengthH + SIPStack.SIP_LINE_DOUBLEEND +
+                            body;
+        } else {
+            sipCall.message =
+                    String.valueOf(sipCall.commandLine) + SIPStack.SIP_LINE_END +
+                            sipCall.viaH + SIPStack.SIP_LINE_END +
+                            sipCall.maxforwardH + SIPStack.SIP_LINE_END +
+                            sipCall.contactH + SIPStack.SIP_LINE_END +
+                            sipCall.fromH + SIPStack.SIP_LINE_END +
+                            sipCall.toH + SIPStack.SIP_LINE_END +
+                            sipCall.callidH + SIPStack.SIP_LINE_END +
+                            sipCall.cseqH + SIPStack.SIP_LINE_END +
+                            sipCall.allowH + SIPStack.SIP_LINE_END +
+                            sipCall.useragentH + SIPStack.SIP_LINE_END +
+                            header +
+                            sipCall.contenttypeH +
+                            sipCall.contentlengthH + SIPStack.SIP_LINE_DOUBLEEND +
+                            body;
+        }
+        return true;
+    }
+
+    public boolean INVITEParser_action_0(SIPCall sipCall, String message) {
+        try {
+            SIPRequestLine requestLine = new SIPRequestLine(message);
+            if (requestLine != null &&
+                    sipCall != null &&
+                    sipCall.flag &&
+                    sipCall.callDirection == SIPStack.SIP_CALLDIRECTION_OUT) {
+                SIPHeader sipHeader = new SIPHeader(message, SIPStack.SIP_HEADERTYPE_CALLID);
+                boolean bValidCall = false;
+                if (sipHeader != null && sipHeader.flag)
+                    if (sipHeader.headerValue != null &&
+                            sipHeader.headerValue.length() > 0 &&
+                            sipCall.callId != null &&
+                            sipHeader.headerValue.compareTo(sipCall.callId) == 0) {
+                        SIPHeader seqHeader = new SIPHeader(message, SIPStack.SIP_HEADERTYPE_CSEQ);
+                        if (seqHeader != null && seqHeader.callSequenceNumber() == sipCall.CSEQ_NUMBER) {
+                            sipCall.responseCode = requestLine.code;
+                            //Log.e(TAG, "[INVITEParser] ============ requestLine.code ============ ");
+                            return true;
+                        }
+                    }
+            }
+        } catch (Exception exception) {}
+        return false;
+    }
+
+    public boolean ACKParser_action_0(SIPCall sipCall, String message) {
+        try {
+            if (sipCall.callState == 23 ||
+                    sipCall.callState == 24) {
+                SIPRequestLine requestLine = new SIPRequestLine(message);
+                if (requestLine != null) {
+                    SIPHeader sipHeader = new SIPHeader(message, SIPStack.SIP_HEADERTYPE_CALLID);
+                    boolean bValidCall = false;
+                    if (sipHeader != null && sipHeader.flag)
+                        if (sipHeader.headerValue != null &&
+                                sipHeader.headerValue.length() > 0 &&
+                                sipCall.callId != null &&
+                                sipHeader.headerValue.compareTo(sipCall.callId) == 0)
+                            bValidCall = true;
+                    if (bValidCall) {
+                        sipHeader = new SIPHeader(message, SIPStack.SIP_HEADERTYPE_CSEQ);
+                        if (sipHeader != null && sipHeader.flag) {
+                            sipCall.ACK_CSEQ = sipHeader.callSequenceNumber();
+                            sipCall.callMode = SIPStack.SIP_CALLMODE_BASIC;
+                            sipCall.callState = 7;
+                            sipCall.resetUpdateheaders();
+                            return true;
+                        }
+                    }
+                }
+            }
+        } catch (Exception exception) {}
+        return false;
+    }
+
+    public boolean ACKParser_action_1(SIPCall sipCall, String message) {
+        try {
+            SIPRequestLine requestLine = new SIPRequestLine(message);
+            if (requestLine != null) {
+                boolean bValidCall = false;
+                SIPHeader sipHeader = new SIPHeader(message, SIPStack.SIP_HEADERTYPE_CALLID);
+                if (sipHeader != null && sipHeader.flag)
+                    if (sipHeader.headerValue != null &&
+                            sipHeader.headerValue.length() > 0 &&
+                            sipCall.callId != null &&
+                            sipHeader.headerValue.compareTo(sipCall.callId) == 0)
+                        bValidCall = true;
+                if (bValidCall) {
+                    sipHeader = new SIPHeader(message, SIPStack.SIP_HEADERTYPE_CSEQ);
+                    if (sipHeader != null && sipHeader.flag) {
+                        sipCall.ACK_CSEQ = sipHeader.callSequenceNumber();
+                        sipCall.callState = 7;
+                        return true;
+                    }
+                }
+            }
+        } catch (Exception exception) {}
+        return false;
+    }
+
+    public boolean ACKParser_action_2(SIPCall sipCall, String message) {
+        try {
+            boolean bValidCall = false;
+            SIPHeader sipHeader = new SIPHeader(message, SIPStack.SIP_HEADERTYPE_CALLID);
+            if (sipHeader != null && sipHeader.flag)
+                if (sipHeader.headerValue != null &&
+                        sipHeader.headerValue.length() > 0 &&
+                        sipCall.callId != null &&
+                        sipHeader.headerValue.compareTo(sipCall.callId) == 0)
+                    return true;
+        } catch (Exception exception) {}
+        return false;
+    }
+
+    public boolean CANCELParser_action_0(SIPCall sipCall, String message) {
+        try {
+            SIPRequestLine requestLine = new SIPRequestLine(message);
+            if (requestLine != null) {
+                SIPHeader sipHeader = new SIPHeader(message, SIPStack.SIP_HEADERTYPE_CALLID);
+                boolean bValidCall = false;
+                if (sipHeader != null && sipHeader.flag)
+                    if (sipHeader.headerValue != null &&
+                            sipHeader.headerValue.length() > 0 &&
+                            sipCall.callId != null &&
+                            sipHeader.headerValue.compareTo(sipCall.callId) == 0)
+                        bValidCall = true;
+                if (bValidCall) {
+                    sipHeader = new SIPHeader(message, SIPStack.SIP_HEADERTYPE_CSEQ);
+                    if (sipHeader != null && sipHeader.flag) {
+                        sipCall.CANCEL_CSEQ = sipHeader.callSequenceNumber();
+                        sipCall.callState = 12;
+                        return true;
+                    }
+                }
+            }
+        } catch (Exception exception) {}
+        return false;
+    }
+
+    public boolean CANCELParser_action_1(SIPCall sipCall, String message) {
+        try {
+            SIPRequestLine requestLine = new SIPRequestLine(message);
+            SIPHeader sipHeader = new SIPHeader(message, SIPStack.SIP_HEADERTYPE_CALLID);
+            boolean bValidCall = false;
+            if (sipHeader != null && sipHeader.flag)
+                if (sipHeader.headerValue != null &&
+                        sipHeader.headerValue.length() > 0 &&
+                        sipCall.callId != null &&
+                        sipHeader.headerValue.compareTo(sipCall.callId) == 0)
+                    bValidCall = true;
+            if (bValidCall) {
+                if (requestLine.code != 401);
+                return true;
+            }
+        } catch (Exception exception) {}
+        return false;
+    }
+
+    public String makeAcceptCancelRequest(SIPCall sipCall, String message) {
+        try {
+            if (sipCall == null || !sipCall.flag)
+                return "";
+            sipCall.BYE_CSEQ = sipCall.ACK_CSEQ;
+            String commandLine = null;
+            String viaH = null;
+            String maxforwardH = null;
+            String contactH = null;
+            String toH = null;
+            String fromH = null;
+            String callidH = null;
+            String cseqH = null;
+            String expiresH = null;
+            String allowH = null;
+            String useragentH = null;
+            String contentlengthH = null;
+            commandLine = "SIP/2.0 200 " + SIPStack.getResponseDescription(200) + SIPStack.SIP_LINE_END;
+            SIPHeader sipHeader = new SIPHeader(message, SIPStack.SIP_HEADERTYPE_VIA);
+            if (sipHeader != null && sipHeader.flag) {
+                viaH = String.valueOf(sipHeader.header) + SIPStack.SIP_LINE_END;
+            } else {
+                viaH = "";
+            }
+            sipHeader = new SIPHeader(message, SIPStack.SIP_HEADERTYPE_FROM);
+            if (sipHeader != null && sipHeader.flag) {
+                fromH = String.valueOf(sipHeader.header) + SIPStack.SIP_LINE_END;
+            } else {
+                fromH = "";
+            }
+            sipHeader = new SIPHeader(message, SIPStack.SIP_HEADERTYPE_TO);
+            if (sipHeader != null && sipHeader.flag) {
+                toH = String.valueOf(sipHeader.header) + SIPStack.SIP_LINE_END;
+                if (toH.indexOf("tag=") < 0)
+                    toH = String.valueOf(sipHeader.header) + ";tag=" + SIPStack.newTag() + SIPStack.SIP_LINE_END;
+            } else {
+                toH = "";
+            }
+            sipHeader = new SIPHeader(message, SIPStack.SIP_HEADERTYPE_CALLID);
+            if (sipHeader != null && sipHeader.flag) {
+                callidH = String.valueOf(sipHeader.header) + SIPStack.SIP_LINE_END;
+            } else {
+                callidH = "";
+            }
+            sipHeader = new SIPHeader(message, SIPStack.SIP_HEADERTYPE_CSEQ);
+            if (sipHeader != null && sipHeader.flag) {
+                sipCall.CANCEL_CSEQ = sipHeader.callSequenceNumber();
+                cseqH = String.valueOf(sipHeader.header) + SIPStack.SIP_LINE_END;
+            } else {
+                cseqH = "";
+            }
+            contentlengthH = "Content-Length: 0\r\n";
+            String sendmessage =
+                    String.valueOf(commandLine) +
+                            viaH +
+                            fromH +
+                            toH +
+                            callidH +
+                            cseqH +
+                            contentlengthH + SIPStack.SIP_LINE_END;
+            return sendmessage;
+        } catch (Exception exception) {
+            return "";
+        }
+    }
+
+    public String makeSendProgressingwithbody(SIPCall sipCall) {
+        try {
+            String commandLine = null;
+            String contactH = null;
+            String contentlengthH = null;
+            commandLine = "SIP/2.0 183 " + SIPStack.getResponseDescription(183) + SIPStack.SIP_LINE_END;
+            String viaString = "";
+            if (sipCall.viaArray.length() > 0)
+                viaString = sipCall.viaArray.toString();
+            String routeString = "";
+            if (sipCall.recordrouteArray.length() > 0)
+                routeString = sipCall.recordrouteArray.toString();
+            if (this.ifIp != null && this.ifIp.length() > 0 && this.ifPort > 0) {
+                contactH = "Contact: <sip:" + this.id + "@" + this.ifIp + ":" + this.ifPort + ">";
+            } else {
+                contactH = "Contact: <sip:" + this.id + "@" + sipCall.localIp + ":" + sipCall.localPort + ">";
+            }
+            String contenttypeString = "";
+            String bodyString = "";
+            if (sipCall.sdp != null && sipCall.sdp.flag) {
+                String body = "";
+                if (SIPStack.bVideocommunication) {
+                    body = String.valueOf(sipCall.sdp.getFinalBodyString()) + getVideomediadescription(sipCall.sdp.audioM.mediaPort + 2);
+                } else {
+                    body = sipCall.sdp.getFinalBodyString();
+                }
+                if (body != null && body.length() > 0) {
+                    bodyString = body;
+                    contenttypeString = "Content-Type: application/SDP\r\n";
+                }
+            }
+            contentlengthH = "Content-Length: " + bodyString.length() + SIPStack.SIP_LINE_END;
+            String sendmessage =
+                    String.valueOf(commandLine) +
+                            viaString +
+                            routeString +
+                            sipCall.fromH + SIPStack.SIP_LINE_END +
+                            sipCall.toH + SIPStack.SIP_LINE_END +
+                            sipCall.callidH + SIPStack.SIP_LINE_END +
+                            sipCall.cseqH + SIPStack.SIP_LINE_END +
+                            contactH + SIPStack.SIP_LINE_END +
+                            contenttypeString +
+                            contentlengthH + SIPStack.SIP_LINE_END +
+                            bodyString;
+            return sendmessage;
+        } catch (Exception exception) {
+            return "";
+        }
+    }
+
+    public String makeSendProgressing(SIPCall sipCall) {
+        try {
+            if (sipCall == null || !sipCall.flag)
+                return "";
+            String commandLine = null;
+            String contactH = null;
+            String contentlengthH = null;
+            commandLine = "SIP/2.0 180 " + SIPStack.getResponseDescription(180) + SIPStack.SIP_LINE_END;
+            String viaString = "";
+            if (sipCall.viaArray.length() > 0)
+                viaString = sipCall.viaArray.toString();
+            String routeString = "";
+            if (sipCall.recordrouteArray != null &&
+                    sipCall.recordrouteArray.length() > 0)
+                routeString = sipCall.recordrouteArray.toString();
+            if (this.ifIp != null && this.ifIp.length() > 0 && this.ifPort > 0) {
+                contactH = "Contact: <sip:" + this.id + "@" + this.ifIp + ":" + this.ifPort + ">";
+            } else {
+                contactH = "Contact: <sip:" + this.id + "@" + sipCall.localIp + ":" + sipCall.localPort + ">";
+            }
+            contentlengthH = "Content-Length: 0\r\n";
+            String sendmessage =
+                    String.valueOf(commandLine) +
+                            viaString +
+                            routeString +
+                            sipCall.fromH + SIPStack.SIP_LINE_END +
+                            sipCall.toH + SIPStack.SIP_LINE_END +
+                            sipCall.callidH + SIPStack.SIP_LINE_END +
+                            sipCall.cseqH + SIPStack.SIP_LINE_END +
+                            contactH + SIPStack.SIP_LINE_END +
+                            contentlengthH + SIPStack.SIP_LINE_END;
+            return sendmessage;
+        } catch (Exception exception) {
+            return "";
+        }
+    }
+
+    public String makeSendProceeding(SIPCall sipCall) {
+        try {
+            if (sipCall == null || !sipCall.flag)
+                return "";
+            String commandLine = null;
+            String contactH = null;
+            String contentlengthH = null;
+            commandLine = "SIP/2.0 100 " + SIPStack.getResponseDescription(100) + SIPStack.SIP_LINE_END;
+            String viaString = "";
+            if (sipCall.viaArray.length() > 0)
+                viaString = sipCall.viaArray.toString();
+            String routeString = "";
+            if (sipCall.recordrouteArray != null &&
+                    sipCall.recordrouteArray.length() > 0)
+                routeString = sipCall.recordrouteArray.toString();
+            if (this.ifIp != null && this.ifIp.length() > 0 && this.ifPort > 0) {
+                contactH = "Contact: <sip:" + this.id + "@" + this.ifIp + ":" + this.ifPort + ">";
+            } else {
+                contactH = "Contact: <sip:" + this.id + "@" + sipCall.localIp + ":" + sipCall.localPort + ">";
+            }
+            contentlengthH = "Content-Length: 0\r\n";
+            String sendmessage =
+                    String.valueOf(commandLine) +
+                            viaString +
+                            routeString +
+                            sipCall.fromH + SIPStack.SIP_LINE_END +
+                            sipCall.toH + SIPStack.SIP_LINE_END +
+                            sipCall.callidH + SIPStack.SIP_LINE_END +
+                            sipCall.cseqH + SIPStack.SIP_LINE_END +
+                            contactH + SIPStack.SIP_LINE_END +
+                            contentlengthH + SIPStack.SIP_LINE_END;
+            return sendmessage;
+        } catch (Exception exception) {
+            return "";
+        }
+    }
+
+    public String makeSendAccept(SIPCall sipCall) {
+        try {
+            if (sipCall == null || !sipCall.flag)
+                return "";
+            if (sipCall.callDirection == SIPStack.SIP_CALLDIRECTION_IN &&
+                    sipCall.callState == 2) {
+                String commandLine = null;
+                String contactH = null;
+                String contentlengthH = null;
+                commandLine = "SIP/2.0 200 " + SIPStack.getResponseDescription(200) + SIPStack.SIP_LINE_END;
+                String viaString = "";
+                if (sipCall.viaArray.length() > 0)
+                    viaString = sipCall.viaArray.toString();
+                String routeString = "";
+                if (sipCall.recordrouteArray.length() > 0)
+                    routeString = sipCall.recordrouteArray.toString();
+                if (this.ifIp != null && this.ifIp.length() > 0 && this.ifPort > 0) {
+                    contactH = "Contact: <sip:" + this.id + "@" + this.ifIp + ":" + this.ifPort + ">";
+                } else {
+                    contactH = "Contact: <sip:" + this.id + "@" + sipCall.localIp + ":" + sipCall.localPort + ">";
+                }
+                String contenttypeString = "";
+                String bodyString = "";
+                if (sipCall.sdp != null && sipCall.sdp.flag) {
+                    String body = "";
+                    if (SIPStack.bVideocommunication) {
+                        body = String.valueOf(sipCall.sdp.getFinalBodyString()) + getVideomediadescription(sipCall.sdp.audioM.mediaPort + 2);
+                    } else {
+                        body = sipCall.sdp.getFinalBodyString();
+                    }
+                    if (body != null && body.length() > 0) {
+                        bodyString = body;
+                        contenttypeString = "Content-Type: application/SDP\r\n";
+                    }
+                }
+                contentlengthH = "Content-Length: " + bodyString.length() + SIPStack.SIP_LINE_END;
+                String sendmessage =
+                        String.valueOf(commandLine) +
+                                viaString +
+                                routeString +
+                                sipCall.fromH + SIPStack.SIP_LINE_END +
+                                sipCall.toH + SIPStack.SIP_LINE_END +
+                                sipCall.callidH + SIPStack.SIP_LINE_END +
+                                sipCall.cseqH + SIPStack.SIP_LINE_END +
+                                contactH + SIPStack.SIP_LINE_END +
+                                contenttypeString +
+                                contentlengthH + SIPStack.SIP_LINE_END +
+                                bodyString;
+                return sendmessage;
+            }
+        } catch (Exception exception) {}
+        return "";
+    }
+
+    public String makeDirectsendAccept(SIPCall sipCall) {
+        try {
+            if (sipCall == null || !sipCall.flag)
+                return "";
+            if (sipCall.callDirection == SIPStack.SIP_CALLDIRECTION_IN &&
+                    sipCall.callState == 2) {
+                String commandLine = null;
+                String contactH = null;
+                String contentlengthH = null;
+                commandLine = "SIP/2.0 200 " + SIPStack.getResponseDescription(200) + SIPStack.SIP_LINE_END;
+                String viaString = "";
+                if (sipCall.viaArray.length() > 0)
+                    viaString = sipCall.viaArray.toString();
+                String routeString = "";
+                if (sipCall.recordrouteArray.length() > 0)
+                    routeString = sipCall.recordrouteArray.toString();
+                if (this.ifIp != null && this.ifIp.length() > 0 && this.ifPort > 0) {
+                    contactH = "Contact: <sip:" + this.id + "@" + this.ifIp + ":" + this.ifPort + ">";
+                } else {
+                    contactH = "Contact: <sip:" + this.id + "@" + sipCall.localIp + ":" + sipCall.localPort + ">";
+                }
+                String contenttypeString = "";
+                String bodyString = "";
+                if (sipCall.sdp != null && sipCall.sdp.flag) {
+                    String body = "";
+                    if (SIPStack.bVideocommunication) {
+                        body = String.valueOf(sipCall.sdp.getFinalBodyString()) + getVideomediadescription(sipCall.sdp.audioM.mediaPort + 2);
+                    } else {
+                        body = sipCall.sdp.getFinalBodyString();
+                    }
+                    if (body != null && body.length() > 0) {
+                        bodyString = body;
+                        contenttypeString = "Content-Type: application/SDP\r\n";
+                    }
+                }
+                contentlengthH = "Content-Length: " + bodyString.length() + SIPStack.SIP_LINE_END;
+                String sendmessage =
+                        String.valueOf(commandLine) +
+                                viaString +
+                                routeString +
+                                sipCall.fromH + SIPStack.SIP_LINE_END +
+                                sipCall.toH + SIPStack.SIP_LINE_END +
+                                sipCall.callidH + SIPStack.SIP_LINE_END +
+                                sipCall.cseqH + SIPStack.SIP_LINE_END +
+                                contactH + SIPStack.SIP_LINE_END +
+                                contenttypeString +
+                                contentlengthH + SIPStack.SIP_LINE_END +
+                                bodyString;
+                return sendmessage;
+            }
+        } catch (Exception exception) {}
+        return "";
+    }
+
+    public boolean makeCallMake(SIPCall sipCall, String number) {
+        try {
+            String header = "";
+            if (sipCall == null || sipCall.flag)
+                return false;
+            sipCall.CSEQ_NUMBER = SIPStack.SIP_SEQUENCE_INVITE;
+            SIPStack.SIP_SEQUENCE_INVITE++;
+            if (SIPStack.SIP_SEQUENCE_INVITE > 65556)
+                SIPStack.SIP_SEQUENCE_INVITE = 1;
+            if (!sipCall.activeCallHandle(
+                    this.id,
+                    this.cid,
+                    this.authid,
+                    this.authpassword,
+                    number,
+                    this.serverIp,
+                    this.serverPort,
+                    this.serverDomain,
+                    this.localIp,
+                    this.localPort))
+                return false;
+            if (number.length() <= 0)
+                return false;
+            sipCall.commandLine = "INVITE sip:" + number + "@" + this.serverDomain + ":" + this.serverPort + " SIP/2.0";
+            Date today = new Date();
+            sipCall.viaBranch = SIPStack.getViaBranch();
+            sipCall.viaH = "Via: SIP/2.0/UDP " + this.localIp + ":" + this.localPort + ";branch=" + sipCall.viaBranch + ";rport";
+            sipCall.maxforwardH = "Max-Forwards: 70";
+            if (this.ifIp != null && this.ifIp.length() > 0 && this.ifPort > 0) {
+                sipCall.contactH = "Contact: <sip:" + this.id + "@" + this.ifIp + ":" + this.ifPort + ">";
+            } else {
+                sipCall.contactH = "Contact: <sip:" + this.id + "@" + sipCall.localIp + ":" + sipCall.localPort + ">";
+            }
+            sipCall.toH = "To: \"" + number + "\"<sip:" + number + "@" + sipCall.serverDomain + ":" + sipCall.serverPort + ">";
+            sipCall.fromTag = SIPStack.newTag();
+            sipCall.fromH = "From: \"" + sipCall.id + "\"<sip:" + sipCall.id + "@" + sipCall.serverDomain + ":" + sipCall.serverPort + ">;tag=" + sipCall.fromTag;
+            sipCall.callId = String.valueOf(SIPStack.BSSMD5Get(this.viaH)) + SIPStack.BSSMD5Get("1198602188") + today.getSeconds() + ".";
+            sipCall.callidH = "Call-ID: " + sipCall.callId;
+            sipCall.cseqH = "CSeq: " + sipCall.CSEQ_NUMBER + " INVITE";
+            sipCall.allowH = "Allow: INVITE, ACK, CANCEL, OPTIONS, BYE, REFER, NOTIFY, MESSAGE, SUBSCRIBE, INFO";
+            sipCall.useragentH = "User-Agent: KwangHaeSoft SmartSip release 0100o";
+            if (sipCall.cid != null && sipCall.cid.length() > 0) {
+                sipCall.passertedidentityH = "P-Asserted-Identity: <sip:" + sipCall.cid + "@" + sipCall.localIp + ":" + sipCall.localPort + ">";
+                header = "P-Asserted-Identity: <sip:" + sipCall.cid + "@" + sipCall.localIp + ":" + sipCall.localPort + ">" + SIPStack.SIP_LINE_END;
+            } else {
+                sipCall.passertedidentityH = null;
+                header = "";
+            }
+            int audioport = SIPStack.getFreeAudioRtpPort();
+            if (audioport > 0)
+                sipCall.constructSdp();
+            if (sipCall.sdp != null && sipCall.sdp.flag) {
+                sipCall.sdp.setMediaPort(SIPStack.SIP_MEDIATYPE_AUDIO, audioport);
+                if (SIPStack.PRIMARY_CODEC_AUDIO == SIPStack.SIP_CODEC_G711U) {
+                    sipCall.sdp.setCodec(
+                            SIPStack.SIP_MEDIATYPE_AUDIO,
+                            SIPStack.SIP_CODEC_G711U,
+                            "PCMU/8000");
+                    sipCall.sdp.setCodec(
+                            SIPStack.SIP_MEDIATYPE_AUDIO,
+                            SIPStack.SIP_CODEC_G711A,
+                            "PCMA/8000");
+                } else {
+                    sipCall.sdp.setCodec(
+                            SIPStack.SIP_MEDIATYPE_AUDIO,
+                            SIPStack.SIP_CODEC_G711A,
+                            "PCMA/8000");
+                    sipCall.sdp.setCodec(
+                            SIPStack.SIP_MEDIATYPE_AUDIO,
+                            SIPStack.SIP_CODEC_G711U,
+                            "PCMU/8000");
+                }
+                sipCall.sdp.setCodec(
+                        SIPStack.SIP_MEDIATYPE_AUDIO,
+                        RFC2833.payloadType,
+                        "telephone-event/8000");
+                sipCall.sdp.setFmtpDescribe(SIPStack.SIP_MEDIATYPE_AUDIO, RFC2833.payloadType, "0-15");
+            }
+            String body = null;
+            sipCall.contenttypeH = "";
+            if (sipCall.sdp != null && sipCall.sdp.flag) {
+                sipCall.contenttypeH = "Content-Type: application/SDP\r\n";
+                if (SIPStack.bVideocommunication) {
+                    body = String.valueOf(sipCall.sdp.getBodyString()) + getVideomediadescription(sipCall.sdp.audioM.mediaPort + 2);
+                } else {
+                    body = sipCall.sdp.getBodyString();
+                }
+                sipCall.contentlengthH = "Content-Length: " + body.length();
+            } else {
+                body = "";
+                sipCall.contentlengthH = "Content-Length: 0";
+            }
+            sipCall.callState = 1;
+            sipCall.callDirection = SIPStack.SIP_CALLDIRECTION_OUT;
+            if (sipCall.authorizationINVITEH != null && sipCall.authorizationINVITEH.length() > 0) {
+                sipCall.message =
+                        String.valueOf(sipCall.commandLine) + SIPStack.SIP_LINE_END +
+                                sipCall.viaH + SIPStack.SIP_LINE_END +
+                                sipCall.maxforwardH + SIPStack.SIP_LINE_END +
+                                sipCall.contactH + SIPStack.SIP_LINE_END +
+                                sipCall.fromH + SIPStack.SIP_LINE_END +
+                                sipCall.toH + SIPStack.SIP_LINE_END +
+                                sipCall.callidH + SIPStack.SIP_LINE_END +
+                                sipCall.cseqH + SIPStack.SIP_LINE_END +
+                                sipCall.allowH + SIPStack.SIP_LINE_END +
+                                sipCall.useragentH + SIPStack.SIP_LINE_END +
+                                header +
+                                sipCall.authorizationINVITEH + SIPStack.SIP_LINE_END +
+                                sipCall.contenttypeH +
+                                sipCall.contentlengthH + SIPStack.SIP_LINE_DOUBLEEND +
+                                body;
+                return true;
+            }
+            sipCall.message =
+                    String.valueOf(sipCall.commandLine) + SIPStack.SIP_LINE_END +
+                            sipCall.viaH + SIPStack.SIP_LINE_END +
+                            sipCall.maxforwardH + SIPStack.SIP_LINE_END +
+                            sipCall.contactH + SIPStack.SIP_LINE_END +
+                            sipCall.fromH + SIPStack.SIP_LINE_END +
+                            sipCall.toH + SIPStack.SIP_LINE_END +
+                            sipCall.callidH + SIPStack.SIP_LINE_END +
+                            sipCall.cseqH + SIPStack.SIP_LINE_END +
+                            sipCall.allowH + SIPStack.SIP_LINE_END +
+                            sipCall.useragentH + SIPStack.SIP_LINE_END +
+                            header +
+                            sipCall.contenttypeH +
+                            sipCall.contentlengthH + SIPStack.SIP_LINE_DOUBLEEND +
+                            body;
+            return true;
+        } catch (Exception exception) {
+            return false;
+        }
+    }
+
+    public boolean makeSendReInvite(SIPCall sipCall) {
+        try {
+            String header = null;
+            if (sipCall == null || !sipCall.flag)
+                return false;
+            sipCall.viaH = "Via: SIP/2.0/UDP " + this.localIp + ":" + this.localPort + ";branch=" + sipCall.viaBranch + ";rport";
+            sipCall.cseqH = "CSeq: " + sipCall.CSEQ_NUMBER + " INVITE";
+            sipCall.callState = 1;
+            sipCall.callDirection = SIPStack.SIP_CALLDIRECTION_OUT;
+            String body = null;
+            sipCall.contenttypeH = "";
+            if (sipCall.sdp != null && sipCall.sdp.flag) {
+                sipCall.contenttypeH = "Content-Type: application/SDP\r\n";
+                if (SIPStack.bVideocommunication) {
+                    body = String.valueOf(sipCall.sdp.getBodyString()) + getVideomediadescription(sipCall.sdp.audioM.mediaPort + 2);
+                } else {
+                    body = sipCall.sdp.getBodyString();
+                }
+                sipCall.contentlengthH = "Content-Length: " + body.length();
+            } else {
+                body = "";
+                sipCall.contentlengthH = "Content-Length: 0";
+            }
+            if (sipCall.cid != null && sipCall.cid.length() > 0) {
+                sipCall.passertedidentityH = "P-Asserted-Identity: <sip:" + sipCall.cid + "@" + sipCall.localIp + ":" + sipCall.localPort + ">";
+                header = "P-Asserted-Identity: <sip:" + sipCall.cid + "@" + sipCall.localIp + ":" + sipCall.localPort + ">" + SIPStack.SIP_LINE_END;
+            } else {
+                sipCall.passertedidentityH = null;
+                header = "";
+            }
+            if (sipCall.authorizationINVITEH != null && sipCall.authorizationINVITEH.length() > 0) {
+                sipCall.message =
+                        String.valueOf(sipCall.commandLine) + SIPStack.SIP_LINE_END +
+                                sipCall.viaH + SIPStack.SIP_LINE_END +
+                                sipCall.maxforwardH + SIPStack.SIP_LINE_END +
+                                sipCall.contactH + SIPStack.SIP_LINE_END +
+                                sipCall.fromH + SIPStack.SIP_LINE_END +
+                                sipCall.toH + SIPStack.SIP_LINE_END +
+                                sipCall.callidH + SIPStack.SIP_LINE_END +
+                                sipCall.cseqH + SIPStack.SIP_LINE_END +
+                                sipCall.allowH + SIPStack.SIP_LINE_END +
+                                sipCall.useragentH + SIPStack.SIP_LINE_END +
+                                header +
+                                sipCall.authorizationINVITEH + SIPStack.SIP_LINE_END +
+                                sipCall.contenttypeH +
+                                sipCall.contentlengthH + SIPStack.SIP_LINE_DOUBLEEND +
+                                body;
+                return true;
+            }
+            sipCall.message =
+                    String.valueOf(sipCall.commandLine) + SIPStack.SIP_LINE_END +
+                            sipCall.viaH + SIPStack.SIP_LINE_END +
+                            sipCall.maxforwardH + SIPStack.SIP_LINE_END +
+                            sipCall.contactH + SIPStack.SIP_LINE_END +
+                            sipCall.fromH + SIPStack.SIP_LINE_END +
+                            sipCall.toH + SIPStack.SIP_LINE_END +
+                            sipCall.callidH + SIPStack.SIP_LINE_END +
+                            sipCall.cseqH + SIPStack.SIP_LINE_END +
+                            sipCall.allowH + SIPStack.SIP_LINE_END +
+                            sipCall.useragentH + SIPStack.SIP_LINE_END +
+                            header +
+                            sipCall.contenttypeH +
+                            sipCall.contentlengthH + SIPStack.SIP_LINE_DOUBLEEND +
+                            body;
+            return true;
+        } catch (Exception exception) {
+            return false;
+        }
+    }
+
+    public String makeRejectCall(SIPCall sipCall, int code) {
+        try {
+            if (sipCall == null || !sipCall.flag)
+                return "";
+            if (sipCall.callDirection == SIPStack.SIP_CALLDIRECTION_IN)
+                if (sipCall.callState == 2 ||
+                        sipCall.callState == 12) {
+                    String commandLine = null;
+                    String contactH = null;
+                    String contentlengthH = null;
+                    commandLine = "SIP/2.0 " + code + " " + SIPStack.getResponseDescription(code) + SIPStack.SIP_LINE_END;
+                    String viaString = "";
+                    if (sipCall.viaArray.length() > 0)
+                        viaString = sipCall.viaArray.toString();
+                    String routeString = "";
+                    if (sipCall.recordrouteArray.length() > 0)
+                        routeString = sipCall.recordrouteArray.toString();
+                    if (this.ifIp != null && this.ifIp.length() > 0 && this.ifPort > 0) {
+                        contactH = "Contact: <sip:" + this.id + "@" + this.ifIp + ":" + this.ifPort + ">";
+                    } else {
+                        contactH = "Contact: <sip:" + this.id + "@" + sipCall.localIp + ":" + sipCall.localPort + ">";
+                    }
+                    contentlengthH = "Content-Length: 0" + SIPStack.SIP_LINE_END;
+                    String sendmessage =
+                            String.valueOf(commandLine) +
+                                    viaString +
+                                    routeString +
+                                    sipCall.fromH + SIPStack.SIP_LINE_END +
+                                    sipCall.toH + SIPStack.SIP_LINE_END +
+                                    sipCall.callidH + SIPStack.SIP_LINE_END +
+                                    sipCall.cseqH + SIPStack.SIP_LINE_END +
+                                    contactH + SIPStack.SIP_LINE_END +
+                                    contentlengthH + SIPStack.SIP_LINE_END;
+                    return sendmessage;
+                }
+        } catch (Exception exception) {}
+        return "";
+    }
+
+    public String makeRejectCall(SIPCall sipCall, int code, String contact) {
+        try {
+            if (sipCall == null || !sipCall.flag)
+                return "";
+            if (sipCall.callDirection == SIPStack.SIP_CALLDIRECTION_IN)
+                if (sipCall.callState == 2 ||
+                        sipCall.callState == 12) {
+                    String commandLine = null;
+                    String contactH = null;
+                    String contentlengthH = null;
+                    commandLine = "SIP/2.0 " + code + " " + SIPStack.getResponseDescription(code) + SIPStack.SIP_LINE_END;
+                    String viaString = "";
+                    if (sipCall.viaArray.length() > 0)
+                        viaString = sipCall.viaArray.toString();
+                    String routeString = "";
+                    if (sipCall.recordrouteArray.length() > 0)
+                        routeString = sipCall.recordrouteArray.toString();
+                    contactH = "Contact: <" + contact + ">";
+                    contentlengthH = "Content-Length: 0" + SIPStack.SIP_LINE_END;
+                    String sendmessage =
+                            String.valueOf(commandLine) +
+                                    viaString +
+                                    routeString +
+                                    sipCall.fromH + SIPStack.SIP_LINE_END +
+                                    sipCall.toH + SIPStack.SIP_LINE_END +
+                                    sipCall.callidH + SIPStack.SIP_LINE_END +
+                                    sipCall.cseqH + SIPStack.SIP_LINE_END +
+                                    contactH + SIPStack.SIP_LINE_END +
+                                    contentlengthH + SIPStack.SIP_LINE_END;
+                    return sendmessage;
+                }
+        } catch (Exception exception) {}
+        return "";
+    }
+
+    public String makeRejectCall(String message, int code, String localIp, int localPort, String remoteIp, int remotePort) {
+        try {
+            if (message == null || message.length() == 0 || remoteIp == null || remoteIp.length() == 0 ||
+                    remotePort <= 0)
+                return "";
+            String viaH = "";
+            StringBuffer viaArray = new StringBuffer();
+            String routeH = "";
+            StringBuffer routeArray = new StringBuffer();
+            String recordrouteH = "";
+            StringBuffer recordrouteArray = new StringBuffer();
+            String contactH = "";
+            String fromH = "";
+            String callidH = "";
+            String cseqH = "";
+            String contentlengthH = "";
+            StringTokenizer tokenArray = new StringTokenizer(message, SIPStack.SIP_LINE_END, true);
+            while (tokenArray.hasMoreTokens()) {
+                String token = tokenArray.nextToken().trim();
+                if (token.length() <= 0 ||
+                        token.compareTo("\r") == 0 ||
+                        token.compareTo("\n") == 0)
+                    continue;
+                if (token.startsWith("From: ")) {
+                    fromH = String.valueOf(token) + SIPStack.SIP_LINE_END;
+                    continue;
+                }
+                if (token.startsWith("f: ")) {
+                    fromH = String.valueOf(token) + SIPStack.SIP_LINE_END;
+                    continue;
+                }
+                if (token.startsWith("To: ")) {
+                    if (token.indexOf("tag=") < 0) {
+                        this.toH = String.valueOf(token) + ";tag=" + (new Date()).getTime() + SIPStack.SIP_LINE_END;
+                        continue;
+                    }
+                    this.toH = String.valueOf(token) + SIPStack.SIP_LINE_END;
+                    continue;
+                }
+                if (token.startsWith("t: ")) {
+                    if (token.indexOf("tag=") < 0) {
+                        this.toH = String.valueOf(token) + ";tag=" + (new Date()).getTime() + SIPStack.SIP_LINE_END;
+                        continue;
+                    }
+                    this.toH = String.valueOf(token) + SIPStack.SIP_LINE_END;
+                    continue;
+                }
+                if (token.startsWith("Via: ")) {
+                    if (viaH == null || viaH.length() == 0) {
+                        viaH = token;
+                        int iS = token.indexOf(";rport=");
+                        if (iS > 0 && token.indexOf(";received=") < 0) {
+                            String s1 = token.substring(0, iS);
+                            int iS_ = token.indexOf(";", iS + 1);
+                            String s2 = null;
+                            if (iS_ > 0) {
+                                s2 = token.substring(iS_ + 1);
+                                if (s1 != null && s2 != null) {
+                                    viaH = String.valueOf(s1) + ";" + s2;
+                                } else if (s1 != null) {
+                                    viaH = s1;
+                                }
+                            } else {
+                                viaH = s1;
+                            }
+                            if (viaH != null && viaH.length() > 0)
+                                viaH = String.valueOf(viaH) + ";received=" + remoteIp + ";rport=" + remotePort;
+                        }
+                        if (viaH != null && viaH.length() > 0)
+                            viaArray.append(String.valueOf(viaH) + SIPStack.SIP_LINE_END);
+                        continue;
+                    }
+                    viaArray.append(String.valueOf(token) + SIPStack.SIP_LINE_END);
+                    continue;
+                }
+                if (token.startsWith("v: ")) {
+                    if (viaH == null || viaH.length() == 0) {
+                        viaH = token;
+                        int iS = token.indexOf(";rport=");
+                        if (iS > 0 && token.indexOf(";received=") < 0) {
+                            String s1 = token.substring(0, iS);
+                            int iS_ = token.indexOf(";", iS + 1);
+                            String s2 = null;
+                            if (iS_ > 0) {
+                                s2 = token.substring(iS_ + 1);
+                                if (s1 != null && s2 != null) {
+                                    viaH = String.valueOf(s1) + ";" + s2;
+                                } else if (s1 != null) {
+                                    viaH = s1;
+                                }
+                            } else {
+                                viaH = s1;
+                            }
+                            if (viaH != null && viaH.length() > 0)
+                                viaH = String.valueOf(viaH) + ";received=" + remoteIp + ";rport=" + remotePort;
+                        }
+                        if (viaH != null && viaH.length() > 0)
+                            viaArray.append(String.valueOf(viaH) + SIPStack.SIP_LINE_END);
+                        continue;
+                    }
+                    viaArray.append(String.valueOf(token) + SIPStack.SIP_LINE_END);
+                    continue;
+                }
+                if (token.startsWith("Record-Route: ")) {
+                    if (recordrouteH == null || recordrouteH.length() == 0) {
+                        routeH = null;
+                        routeArray = new StringBuffer();
+                        recordrouteH = token;
+                        recordrouteArray.append(String.valueOf(recordrouteH) + SIPStack.SIP_LINE_END);
+                        routeArray.append(String.valueOf(token.substring(7)) + SIPStack.SIP_LINE_END);
+                        continue;
+                    }
+                    recordrouteArray.append(String.valueOf(token) + SIPStack.SIP_LINE_END);
+                    routeArray.append(String.valueOf(token.substring(7)) + SIPStack.SIP_LINE_END);
+                    continue;
+                }
+                if (token.startsWith("Call-ID: ")) {
+                    callidH = String.valueOf(token) + SIPStack.SIP_LINE_END;
+                    continue;
+                }
+                if (token.startsWith("i: ")) {
+                    callidH = String.valueOf(token) + SIPStack.SIP_LINE_END;
+                    continue;
+                }
+                if (token.startsWith("CSeq: ")) {
+                    cseqH = String.valueOf(token) + SIPStack.SIP_LINE_END;
+                    continue;
+                }
+                if (token.startsWith("Content-Length: ")) {
+                    contentlengthH = "Content-Length: 0\r\n";
+                    continue;
+                }
+                if (token.startsWith("l: "))
+                    contentlengthH = "Content-Length: 0\r\n";
+            }
+            String commandLine = "SIP/2.0 " + code + " " + SIPStack.getResponseDescription(code) + SIPStack.SIP_LINE_END;
+            String viaString = "";
+            if (viaArray.length() > 0)
+                viaString = viaArray.toString();
+            String routeString = "";
+            if (recordrouteArray.length() > 0)
+                routeString = recordrouteArray.toString();
+            if (this.ifIp != null && this.ifIp.length() > 0 && this.ifPort > 0) {
+                contactH = "Contact: <sip:" + this.id + "@" + this.ifIp + ":" + this.ifPort + ">";
+            } else {
+                contactH = "Contact: <sip:" + this.id + "@" + localIp + ":" + localPort + ">";
+            }
+            contentlengthH = "Content-Length: 0" + SIPStack.SIP_LINE_END;
+            String sendmessage =
+                    String.valueOf(commandLine) +
+                            viaString +
+                            routeString +
+                            fromH +
+                            this.toH +
+                            callidH +
+                            cseqH +
+                            contactH + SIPStack.SIP_LINE_END +
+                            contentlengthH + SIPStack.SIP_LINE_END;
+            return sendmessage;
+        } catch (Exception exception) {
+            return "";
+        }
+    }
+
+    public String makeSendUpdateAccept(SIPCall sipCall) {
+        try {
+            if (sipCall == null || !sipCall.flag)
+                return "";
+            if (sipCall.callDirection == SIPStack.SIP_CALLDIRECTION_IN &&
+                    sipCall.callState == 23) {
+                String commandLine = null;
+                String contactH = null;
+                String contentlengthH = null;
+                commandLine = "SIP/2.0 200 " + SIPStack.getResponseDescription(200) + SIPStack.SIP_LINE_END;
+                String viaString = "";
+                if (sipCall.viaArray.length() > 0)
+                    viaString = sipCall.viaArray.toString();
+                String routeString = "";
+                if (sipCall.recordrouteArray.length() > 0)
+                    routeString = sipCall.recordrouteArray.toString();
+                if (this.ifIp != null && this.ifIp.length() > 0 && this.ifPort > 0) {
+                    sipCall.contactH = "Contact: <sip:" + this.id + "@" + this.ifIp + ":" + this.ifPort + ">";
+                } else {
+                    sipCall.contactH = "Contact: <sip:" + this.id + "@" + sipCall.localIp + ":" + sipCall.localPort + ">";
+                }
+                String contenttypeString = "";
+                String bodyString = "";
+                if (sipCall.sdp != null && sipCall.sdp.flag) {
+                    String body = sipCall.sdp.getFinalBodyString();
+                    if (body != null && body.length() > 0) {
+                        bodyString = body;
+                        contenttypeString = "Content-Type: application/SDP\r\n";
+                    }
+                }
+                contentlengthH = "Content-Length: " + bodyString.length() + SIPStack.SIP_LINE_END;
+                String sendmessage =
+                        String.valueOf(commandLine) +
+                                viaString +
+                                routeString +
+                                sipCall.fromH + SIPStack.SIP_LINE_END +
+                                sipCall.toH + SIPStack.SIP_LINE_END +
+                                sipCall.callidH + SIPStack.SIP_LINE_END +
+                                sipCall.cseqH + SIPStack.SIP_LINE_END +
+                                contactH + SIPStack.SIP_LINE_END +
+                                contenttypeString +
+                                contentlengthH + SIPStack.SIP_LINE_END +
+                                bodyString;
+                return sendmessage;
+            }
+        } catch (Exception exception) {}
+        return "";
+    }
+
+    public boolean makeSendRedirectCall(SIPCall sipCall, String message) {
+        try {
+            String header = null;
+            if (message == null || message.length() == 0)
+                return false;
+            if (sipCall == null || !sipCall.flag)
+                return false;
+            SIPCONTACTHeader contactHeader = new SIPCONTACTHeader(message);
+            if (contactHeader == null || !contactHeader.flag)
+                return false;
+            sipCall.initializeRedirectCall();
+            sipCall.CSEQ_NUMBER = SIPStack.SIP_SEQUENCE_INVITE;
+            SIPStack.SIP_SEQUENCE_INVITE++;
+            if (SIPStack.SIP_SEQUENCE_INVITE > 65556)
+                SIPStack.SIP_SEQUENCE_INVITE = 1;
+            if (contactHeader != null && contactHeader.sipuri != null &&
+                    contactHeader.sipuri.length() > 0) {
+                sipCall.commandLine = "INVITE " + contactHeader.sipuri + " SIP/2.0";
+                sipCall.remoteIp = contactHeader.ip;
+                sipCall.remotePort = contactHeader.port;
+                sipCall.dnis = contactHeader.username;
+                sipCall.serverDomain = contactHeader.ip;
+                sipCall.serverPort = contactHeader.port;
+                BSSVideo.HNS_SERVICE_RECEIVER_SELECTED = BSSVideo.HNS_SERVICE_NEIGHBOR;
+                if (contactHeader.username.startsWith("lobby")) {
+                    BSSVideo.HNS_SERVICE_RECEIVER_SELECTED = BSSVideo.HNS_SERVICE_LOBBY;
+                } else if (contactHeader.username.startsWith("office")) {
+                    BSSVideo.HNS_SERVICE_RECEIVER_SELECTED = BSSVideo.HNS_SERVICE_GUARD;
+                }
+            } else {
+                return false;
+            }
+            Date today = new Date();
+            sipCall.viaBranch = SIPStack.getViaBranch();
+            sipCall.viaH = "Via: SIP/2.0/UDP " + this.localIp + ":" + this.localPort + ";branch=" + sipCall.viaBranch + ";rport";
+            sipCall.maxforwardH = "Max-Forwards: 70";
+            if (this.ifIp != null && this.ifIp.length() > 0 && this.ifPort > 0) {
+                sipCall.contactH = "Contact: <sip:" + this.id + "@" + this.ifIp + ":" + this.ifPort + ">";
+            } else {
+                sipCall.contactH = "Contact: <sip:" + this.id + "@" + sipCall.localIp + ":" + sipCall.localPort + ">";
+            }
+            sipCall.toH = "To: \"" + sipCall.dnis + "\"<sip:" + sipCall.dnis + "@" + sipCall.serverDomain + ":" + sipCall.serverPort + ">";
+            sipCall.fromTag = SIPStack.newTag();
+            sipCall.fromH = "From: \"" + sipCall.id + "\"<sip:" + sipCall.id + "@" + sipCall.serverDomain + ":" + sipCall.serverPort + ">;tag=" + sipCall.fromTag;
+            if (BSSVideo.HNS_SERVICE_ORIGINATOR_SELECTED == BSSVideo.HNS_SERVICE_LOBBY) {
+                String postFix = "";
+                if (BSSVideo.HNS_SERVICE_RECEIVER_SELECTED == BSSVideo.HNS_SERVICE_GUARD) {
+                    postFix = BSSVideo.HNS_POSTFIX_GUARD;
+                    sipCall.hnsReceiverServiceType = BSSVideo.HNS_SERVICE_GUARD;
+                } else if (BSSVideo.HNS_SERVICE_RECEIVER_SELECTED == BSSVideo.HNS_SERVICE_NEIGHBOR) {
+                    postFix = BSSVideo.HNS_POSTFIX_NEIGHBOR;
+                    sipCall.hnsReceiverServiceType = BSSVideo.HNS_SERVICE_NEIGHBOR;
+                } else {
+                    postFix = BSSVideo.HNS_POSTFIX_LOBBY;
+                    sipCall.hnsReceiverServiceType = BSSVideo.HNS_SERVICE_ORIGINATOR_SELECTED;
+                }
+                sipCall.callId = String.valueOf(BSSVideo.HNS_PREFIX_LOBBY) + SIPStack.BSSMD5Get(this.viaH) +
+                        SIPStack.BSSMD5Get("1198602188") + today.getSeconds() + "." + postFix;
+                sipCall.hnsOriginatorServiceType = BSSVideo.HNS_SERVICE_LOBBY;
+                BSSVideo.bProgressvideooffer = true;
+            } else if (BSSVideo.HNS_SERVICE_ORIGINATOR_SELECTED == BSSVideo.HNS_SERVICE_GUARD) {
+                String postFix = "";
+                if (BSSVideo.HNS_SERVICE_RECEIVER_SELECTED == BSSVideo.HNS_SERVICE_GUARD) {
+                    postFix = BSSVideo.HNS_POSTFIX_GUARD;
+                    sipCall.hnsReceiverServiceType = BSSVideo.HNS_SERVICE_GUARD;
+                } else if (BSSVideo.HNS_SERVICE_RECEIVER_SELECTED == BSSVideo.HNS_SERVICE_NEIGHBOR) {
+                    postFix = BSSVideo.HNS_POSTFIX_NEIGHBOR;
+                    sipCall.hnsReceiverServiceType = BSSVideo.HNS_SERVICE_NEIGHBOR;
+                } else {
+                    postFix = BSSVideo.HNS_POSTFIX_GUARD;
+                    sipCall.hnsReceiverServiceType = BSSVideo.HNS_SERVICE_ORIGINATOR_SELECTED;
+                }
+                sipCall.callId = String.valueOf(BSSVideo.HNS_PREFIX_GUARD) + SIPStack.BSSMD5Get(this.viaH) +
+                        SIPStack.BSSMD5Get("1198602188") + today.getSeconds() + "." + postFix;
+                sipCall.hnsOriginatorServiceType = BSSVideo.HNS_SERVICE_GUARD;
+                BSSVideo.bProgressvideooffer = true;
+            } else if (BSSVideo.HNS_SERVICE_ORIGINATOR_SELECTED == BSSVideo.HNS_SERVICE_NEIGHBOR) {
+                String postFix = "";
+                if (BSSVideo.HNS_SERVICE_RECEIVER_SELECTED == BSSVideo.HNS_SERVICE_GUARD) {
+                    postFix = BSSVideo.HNS_POSTFIX_GUARD;
+                    sipCall.hnsReceiverServiceType = BSSVideo.HNS_SERVICE_GUARD;
+                    BSSVideo.bProgressvideooffer = true;
+                } else if (BSSVideo.HNS_SERVICE_RECEIVER_SELECTED == BSSVideo.HNS_SERVICE_NEIGHBOR) {
+                    postFix = BSSVideo.HNS_POSTFIX_NEIGHBOR;
+                    sipCall.hnsReceiverServiceType = BSSVideo.HNS_SERVICE_NEIGHBOR;
+                    BSSVideo.bProgressvideooffer = true;
+                } else {
+                    postFix = BSSVideo.HNS_POSTFIX_NEIGHBOR;
+                    sipCall.hnsReceiverServiceType = BSSVideo.HNS_SERVICE_ORIGINATOR_SELECTED;
+                    BSSVideo.bProgressvideooffer = false;
+                }
+                sipCall.callId = String.valueOf(BSSVideo.HNS_PREFIX_NEIGHBOR) + SIPStack.BSSMD5Get(this.viaH) +
+                        SIPStack.BSSMD5Get("1198602188") + today.getSeconds() + "." + postFix;
+                sipCall.hnsOriginatorServiceType = BSSVideo.HNS_SERVICE_NEIGHBOR;
+            } else {
+                sipCall.callId = String.valueOf(SIPStack.BSSMD5Get(this.viaH)) + SIPStack.BSSMD5Get("1198602188") + today.getSeconds() + ".";
+                sipCall.hnsOriginatorServiceType = BSSVideo.HNS_SERVICE_NONE;
+                sipCall.hnsReceiverServiceType = BSSVideo.HNS_SERVICE_NONE;
+                BSSVideo.bProgressvideooffer = false;
+            }
+            sipCall.callidH = "Call-ID: " + sipCall.callId;
+            sipCall.cseqH = "CSeq: " + sipCall.CSEQ_NUMBER + " INVITE";
+            sipCall.allowH = "Allow: INVITE, ACK, CANCEL, OPTIONS, BYE, REFER, NOTIFY, MESSAGE, SUBSCRIBE, INFO";
+            sipCall.useragentH = "User-Agent: KwangHaeSoft SmartSip release 0100o";
+            if (sipCall.cid != null && sipCall.cid.length() > 0) {
+                sipCall.passertedidentityH = "P-Asserted-Identity: <sip:" + sipCall.cid + "@" + sipCall.localIp + ":" + sipCall.localPort + ">";
+                header = "P-Asserted-Identity: <sip:" + sipCall.cid + "@" + sipCall.localIp + ":" + sipCall.localPort + ">" + SIPStack.SIP_LINE_END;
+            } else {
+                sipCall.passertedidentityH = null;
+                header = "";
+            }
+            int audioport = SIPStack.getFreeAudioRtpPort();
+            if (audioport > 0)
+                sipCall.constructSdp();
+            if (sipCall.sdp != null && sipCall.sdp.flag) {
+                sipCall.sdp.setMediaPort(SIPStack.SIP_MEDIATYPE_AUDIO, audioport);
+                if (SIPStack.PRIMARY_CODEC_AUDIO == SIPStack.SIP_CODEC_G711U) {
+                    sipCall.sdp.setCodec(
+                            SIPStack.SIP_MEDIATYPE_AUDIO,
+                            SIPStack.SIP_CODEC_G711U,
+                            "PCMU/8000");
+                    sipCall.sdp.setCodec(
+                            SIPStack.SIP_MEDIATYPE_AUDIO,
+                            SIPStack.SIP_CODEC_G711A,
+                            "PCMA/8000");
+                } else {
+                    sipCall.sdp.setCodec(
+                            SIPStack.SIP_MEDIATYPE_AUDIO,
+                            SIPStack.SIP_CODEC_G711A,
+                            "PCMA/8000");
+                    sipCall.sdp.setCodec(
+                            SIPStack.SIP_MEDIATYPE_AUDIO,
+                            SIPStack.SIP_CODEC_G711U,
+                            "PCMU/8000");
+                }
+                sipCall.sdp.setCodec(
+                        SIPStack.SIP_MEDIATYPE_AUDIO,
+                        RFC2833.payloadType,
+                        "telephone-event/8000");
+                sipCall.sdp.setFmtpDescribe(SIPStack.SIP_MEDIATYPE_AUDIO, RFC2833.payloadType, "0-15");
+            }
+            String body = null;
+            sipCall.contenttypeH = "";
+            if (sipCall.sdp != null && sipCall.sdp.flag) {
+                sipCall.contenttypeH = "Content-Type: application/SDP\r\n";
+                if (SIPStack.bVideocommunication) {
+                    body = String.valueOf(sipCall.sdp.getBodyString()) + getVideomediadescription(sipCall.sdp.audioM.mediaPort + 2);
+                } else {
+                    body = sipCall.sdp.getBodyString();
+                }
+                sipCall.contentlengthH = "Content-Length: " + body.length();
+            } else {
+                body = "";
+                sipCall.contentlengthH = "Content-Length: 0";
+            }
+            sipCall.callState = 1;
+            sipCall.callDirection = SIPStack.SIP_CALLDIRECTION_OUT;
+            sipCall.message =
+                    String.valueOf(sipCall.commandLine) + SIPStack.SIP_LINE_END +
+                            sipCall.viaH + SIPStack.SIP_LINE_END +
+                            sipCall.maxforwardH + SIPStack.SIP_LINE_END +
+                            sipCall.contactH + SIPStack.SIP_LINE_END +
+                            sipCall.fromH + SIPStack.SIP_LINE_END +
+                            sipCall.toH + SIPStack.SIP_LINE_END +
+                            sipCall.callidH + SIPStack.SIP_LINE_END +
+                            sipCall.cseqH + SIPStack.SIP_LINE_END +
+                            sipCall.allowH + SIPStack.SIP_LINE_END +
+                            sipCall.useragentH + SIPStack.SIP_LINE_END +
+                            header +
+                            sipCall.contenttypeH +
+                            sipCall.contentlengthH + SIPStack.SIP_LINE_DOUBLEEND +
+                            body;
+            return true;
+        } catch (Exception exception) {
+            return false;
+        }
+    }
+
+    public boolean makeReactionForWWWAUTHENTICATE(SIPCall sipCall, String message) {
+        try {
+            String header = null;
+            if (sipCall == null || !sipCall.flag)
+                return false;
+            sipCall.CSEQ_NUMBER = ++SIPStack.SIP_SEQUENCE_INVITE;
+            if (SIPStack.SIP_SEQUENCE_INVITE > 65556)
+                SIPStack.SIP_SEQUENCE_INVITE = 1;
+            sipCall.authorizationINVITEH = "";
+            sipCall.authorizationCANCELH = "";
+            sipCall.authorizationBYEH = "";
+            sipCall.authorizationACKH = "";
+            SIPHeader sipHeader = new SIPHeader(message, SIPStack.SIP_HEADERTYPE_WWWAUTHENTICATE);
+            if (sipHeader == null || !sipHeader.flag)
+                sipHeader = new SIPHeader(message, SIPStack.SIP_HEADERTYPE_WwwAUTHENTICATE);
+            if (sipHeader != null && sipHeader.flag) {
+                SIPAUTHENTICATEHeader authHeader =
+                        new SIPAUTHENTICATEHeader(sipHeader.header, SIPStack.SIP_HEADERTYPE_WWWAUTHENTICATE);
+                if (authHeader == null || !authHeader.flag)
+                    authHeader = new SIPAUTHENTICATEHeader(sipHeader.header, SIPStack.SIP_HEADERTYPE_WwwAUTHENTICATE);
+                if (authHeader != null && authHeader.flag)
+                    if (authHeader.nonceValue.length() > 0 && authHeader.realmValue.length() > 0) {
+                        String qop = authHeader.qopValue;
+                        String uri = "sip:" + this.serverDomain + ":" + this.serverPort;
+                        sipCall.authorizationINVITEH = getAuthorizationHeader(
+                                qop,
+                                this.authid,
+                                authHeader.realmValue,
+                                this.authpassword, uri,
+                                authHeader.nonceValue,
+                                SIPStack.SIP_METHODTYPE_INVITE);
+                        sipCall.authorizationCANCELH = getAuthorizationHeader(
+                                qop,
+                                this.authid,
+                                authHeader.realmValue,
+                                this.authpassword, uri,
+                                authHeader.nonceValue,
+                                SIPStack.SIP_METHODTYPE_CANCEL);
+                        sipCall.authorizationBYEH = getAuthorizationHeader(
+                                qop,
+                                this.authid,
+                                authHeader.realmValue,
+                                this.authpassword, uri,
+                                authHeader.nonceValue,
+                                SIPStack.SIP_METHODTYPE_BYE);
+                        sipCall.authorizationACKH = getAuthorizationHeader(
+                                qop,
+                                this.authid,
+                                authHeader.realmValue,
+                                this.authpassword, uri,
+                                authHeader.nonceValue,
+                                SIPStack.SIP_METHODTYPE_ACK);
+                    }
+            }
+            sipCall.commandLine = "INVITE sip:" + sipCall.dnis + "@" + this.serverDomain + ":" + this.serverPort + " SIP/2.0";
+            sipCall.viaBranch = SIPStack.getViaBranch();
+            sipCall.viaH = "Via: SIP/2.0/UDP " + this.localIp + ":" + this.localPort + ";branch=" + sipCall.viaBranch + ";rport";
+            sipCall.maxforwardH = "Max-Forwards: 70";
+            if (this.ifIp != null && this.ifIp.length() > 0 && this.ifPort > 0) {
+                sipCall.contactH = "Contact: <sip:" + this.id + "@" + this.ifIp + ":" + this.ifPort + ">";
+            } else {
+                sipCall.contactH = "Contact: <sip:" + this.id + "@" + sipCall.localIp + ":" + sipCall.localPort + ">";
+            }
+            sipCall.toH = "To: \"" + sipCall.dnis + "\"<sip:" + sipCall.dnis + "@" + sipCall.serverDomain + ":" + sipCall.serverPort + ">";
+            sipCall.fromTag = SIPStack.newTag();
+            sipCall.fromH = "From: \"" + sipCall.id + "\"<sip:" + sipCall.id + "@" + sipCall.serverDomain + ":" + sipCall.serverPort + ">;tag=" + sipCall.fromTag;
+            sipCall.cseqH = "CSeq: " + sipCall.CSEQ_NUMBER + " INVITE";
+            sipCall.allowH = "Allow: INVITE, ACK, CANCEL, OPTIONS, BYE, REFER, NOTIFY, MESSAGE, SUBSCRIBE, INFO";
+            sipCall.useragentH = "User-Agent: KwangHaeSoft SmartSip release 0100o";
+            if (sipCall.cid != null && sipCall.cid.length() > 0) {
+                sipCall.passertedidentityH = "P-Asserted-Identity: <sip:" + sipCall.cid + "@" + sipCall.localIp + ":" + sipCall.localPort + ">";
+                header = "P-Asserted-Identity: <sip:" + sipCall.cid + "@" + sipCall.localIp + ":" + sipCall.localPort + ">" + SIPStack.SIP_LINE_END;
+            } else {
+                sipCall.passertedidentityH = null;
+                header = "";
+            }
+            if (sipCall.sdp == null) {
+                int audioport = SIPStack.getFreeAudioRtpPort();
+                if (audioport > 0)
+                    sipCall.constructSdp();
+                if (sipCall.sdp != null && sipCall.sdp.flag) {
+                    sipCall.sdp.setMediaPort(SIPStack.SIP_MEDIATYPE_AUDIO, audioport);
+                    if (SIPStack.PRIMARY_CODEC_AUDIO == SIPStack.SIP_CODEC_G711U) {
+                        sipCall.sdp.setCodec(
+                                SIPStack.SIP_MEDIATYPE_AUDIO,
+                                SIPStack.SIP_CODEC_G711U,
+                                "PCMU/8000");
+                        sipCall.sdp.setCodec(
+                                SIPStack.SIP_MEDIATYPE_AUDIO,
+                                SIPStack.SIP_CODEC_G711A,
+                                "PCMA/8000");
+                    } else {
+                        sipCall.sdp.setCodec(
+                                SIPStack.SIP_MEDIATYPE_AUDIO,
+                                SIPStack.SIP_CODEC_G711A,
+                                "PCMA/8000");
+                        sipCall.sdp.setCodec(
+                                SIPStack.SIP_MEDIATYPE_AUDIO,
+                                SIPStack.SIP_CODEC_G711U,
+                                "PCMU/8000");
+                    }
+                    sipCall.sdp.setCodec(
+                            SIPStack.SIP_MEDIATYPE_AUDIO,
+                            RFC2833.payloadType,
+                            "telephone-event/8000");
+                    sipCall.sdp.setFmtpDescribe(SIPStack.SIP_MEDIATYPE_AUDIO, RFC2833.payloadType, "0-15");
+                }
+            }
+            String body = null;
+            sipCall.contenttypeH = "";
+            if (sipCall.sdp != null && sipCall.sdp.flag) {
+                sipCall.contenttypeH = "Content-Type: application/SDP\r\n";
+                if (SIPStack.bVideocommunication) {
+                    body = String.valueOf(sipCall.sdp.getBodyString()) + getVideomediadescription(sipCall.sdp.audioM.mediaPort + 2);
+                } else {
+                    body = sipCall.sdp.getBodyString();
+                }
+                sipCall.contentlengthH = "Content-Length: " + body.length();
+            } else {
+                body = "";
+                sipCall.contentlengthH = "Content-Length: 0";
+            }
+            sipCall.callState = 1;
+            sipCall.callDirection = SIPStack.SIP_CALLDIRECTION_OUT;
+            sipCall.message = "";
+            if (sipCall.authorizationINVITEH != null && sipCall.authorizationINVITEH.length() > 0) {
+                sipCall.message =
+                        String.valueOf(sipCall.commandLine) + SIPStack.SIP_LINE_END +
+                                sipCall.viaH + SIPStack.SIP_LINE_END +
+                                sipCall.maxforwardH + SIPStack.SIP_LINE_END +
+                                sipCall.contactH + SIPStack.SIP_LINE_END +
+                                sipCall.fromH + SIPStack.SIP_LINE_END +
+                                sipCall.toH + SIPStack.SIP_LINE_END +
+                                sipCall.callidH + SIPStack.SIP_LINE_END +
+                                sipCall.cseqH + SIPStack.SIP_LINE_END +
+                                sipCall.allowH + SIPStack.SIP_LINE_END +
+                                sipCall.useragentH + SIPStack.SIP_LINE_END +
+                                header +
+                                sipCall.authorizationINVITEH + SIPStack.SIP_LINE_END +
+                                sipCall.contenttypeH +
+                                sipCall.contentlengthH + SIPStack.SIP_LINE_DOUBLEEND +
+                                body;
+            } else {
+                sipCall.message =
+                        String.valueOf(sipCall.commandLine) + SIPStack.SIP_LINE_END +
+                                sipCall.viaH + SIPStack.SIP_LINE_END +
+                                sipCall.maxforwardH + SIPStack.SIP_LINE_END +
+                                sipCall.contactH + SIPStack.SIP_LINE_END +
+                                sipCall.fromH + SIPStack.SIP_LINE_END +
+                                sipCall.toH + SIPStack.SIP_LINE_END +
+                                sipCall.callidH + SIPStack.SIP_LINE_END +
+                                sipCall.cseqH + SIPStack.SIP_LINE_END +
+                                sipCall.allowH + SIPStack.SIP_LINE_END +
+                                sipCall.useragentH + SIPStack.SIP_LINE_END +
+                                header +
+                                sipCall.contenttypeH +
+                                sipCall.contentlengthH + SIPStack.SIP_LINE_DOUBLEEND +
+                                body;
+            }
+            return true;
+        } catch (Exception exception) {
+            return false;
+        }
+    }
+
+    public boolean makeReactionForPROXYAUTHENTICATE(SIPCall sipCall, String message) {
+        try {
+            String header = null;
+            if (sipCall == null || !sipCall.flag)
+                return false;
+            sipCall.CSEQ_NUMBER = ++SIPStack.SIP_SEQUENCE_INVITE;
+            if (SIPStack.SIP_SEQUENCE_INVITE > 65556)
+                SIPStack.SIP_SEQUENCE_INVITE = 1;
+            sipCall.authorizationINVITEH = "";
+            sipCall.authorizationCANCELH = "";
+            sipCall.authorizationBYEH = "";
+            sipCall.authorizationACKH = "";
+            SIPHeader sipHeader = new SIPHeader(message, SIPStack.SIP_HEADERTYPE_PROXYAUTHENTICATE);
+            if (sipHeader != null && sipHeader.flag) {
+                SIPAUTHENTICATEHeader authHeader =
+                        new SIPAUTHENTICATEHeader(sipHeader.header, SIPStack.SIP_HEADERTYPE_PROXYAUTHENTICATE);
+                if (authHeader.flag)
+                    if (authHeader.nonceValue.length() > 0 && authHeader.realmValue.length() > 0) {
+                        String qop = authHeader.qopValue;
+                        String uri = "sip:" + this.serverDomain + ":" + this.serverPort;
+                        sipCall.authorizationINVITEH = getProxyAuthorizationHeader(
+                                qop,
+                                this.authid,
+                                authHeader.realmValue,
+                                this.authpassword, uri,
+                                authHeader.nonceValue,
+                                SIPStack.SIP_METHODTYPE_INVITE);
+                        sipCall.authorizationCANCELH = getProxyAuthorizationHeader(
+                                qop,
+                                this.authid,
+                                authHeader.realmValue,
+                                this.authpassword, uri,
+                                authHeader.nonceValue,
+                                SIPStack.SIP_METHODTYPE_CANCEL);
+                        sipCall.authorizationBYEH = getProxyAuthorizationHeader(
+                                qop,
+                                this.authid,
+                                authHeader.realmValue,
+                                this.authpassword, uri,
+                                authHeader.nonceValue,
+                                SIPStack.SIP_METHODTYPE_BYE);
+                        sipCall.authorizationACKH = getProxyAuthorizationHeader(
+                                qop,
+                                this.authid,
+                                authHeader.realmValue,
+                                this.authpassword, uri,
+                                authHeader.nonceValue,
+                                SIPStack.SIP_METHODTYPE_ACK);
+                    }
+            }
+            sipCall.commandLine = "INVITE sip:" + sipCall.dnis + "@" + this.serverDomain + ":" + this.serverPort + " SIP/2.0";
+            sipCall.viaBranch = SIPStack.getViaBranch();
+            sipCall.viaH = "Via: SIP/2.0/UDP " + this.localIp + ":" + this.localPort + ";branch=" + sipCall.viaBranch + ";rport";
+            sipCall.maxforwardH = "Max-Forwards: 70";
+            if (this.ifIp != null && this.ifIp.length() > 0 && this.ifPort > 0) {
+                sipCall.contactH = "Contact: <sip:" + this.id + "@" + this.ifIp + ":" + this.ifPort + ">";
+            } else {
+                sipCall.contactH = "Contact: <sip:" + this.id + "@" + sipCall.localIp + ":" + sipCall.localPort + ">";
+            }
+            sipCall.toH = "To: \"" + sipCall.dnis + "\"<sip:" + sipCall.dnis + "@" + sipCall.serverDomain + ":" + sipCall.serverPort + ">";
+            sipCall.fromTag = SIPStack.newTag();
+            sipCall.fromH = "From: \"" + sipCall.id + "\"<sip:" + sipCall.id + "@" + sipCall.serverDomain + ":" + sipCall.serverPort + ">;tag=" + sipCall.fromTag;
+            sipCall.cseqH = "CSeq: " + sipCall.CSEQ_NUMBER + " INVITE";
+            sipCall.allowH = "Allow: INVITE, ACK, CANCEL, OPTIONS, BYE, REFER, NOTIFY, MESSAGE, SUBSCRIBE, INFO";
+            sipCall.useragentH = "User-Agent: KwangHaeSoft SmartSip release 0100o";
+            if (sipCall.cid != null && sipCall.cid.length() > 0) {
+                sipCall.passertedidentityH = "P-Asserted-Identity: <sip:" + sipCall.cid + "@" + sipCall.localIp + ":" + sipCall.localPort + ">";
+                header = "P-Asserted-Identity: <sip:" + sipCall.cid + "@" + sipCall.localIp + ":" + sipCall.localPort + ">" + SIPStack.SIP_LINE_END;
+            } else {
+                sipCall.passertedidentityH = null;
+                header = "";
+            }
+            if (sipCall.sdp == null) {
+                int audioport = SIPStack.getFreeAudioRtpPort();
+                if (audioport > 0)
+                    sipCall.constructSdp();
+                if (sipCall.sdp != null && sipCall.sdp.flag) {
+                    sipCall.sdp.setMediaPort(SIPStack.SIP_MEDIATYPE_AUDIO, audioport);
+                    if (SIPStack.PRIMARY_CODEC_AUDIO == SIPStack.SIP_CODEC_G711U) {
+                        sipCall.sdp.setCodec(
+                                SIPStack.SIP_MEDIATYPE_AUDIO,
+                                SIPStack.SIP_CODEC_G711U,
+                                "PCMU/8000");
+                        sipCall.sdp.setCodec(
+                                SIPStack.SIP_MEDIATYPE_AUDIO,
+                                SIPStack.SIP_CODEC_G711A,
+                                "PCMA/8000");
+                    } else {
+                        sipCall.sdp.setCodec(
+                                SIPStack.SIP_MEDIATYPE_AUDIO,
+                                SIPStack.SIP_CODEC_G711A,
+                                "PCMA/8000");
+                        sipCall.sdp.setCodec(
+                                SIPStack.SIP_MEDIATYPE_AUDIO,
+                                SIPStack.SIP_CODEC_G711U,
+                                "PCMU/8000");
+                    }
+                    sipCall.sdp.setCodec(
+                            SIPStack.SIP_MEDIATYPE_AUDIO,
+                            RFC2833.payloadType,
+                            "telephone-event/8000");
+                    sipCall.sdp.setFmtpDescribe(SIPStack.SIP_MEDIATYPE_AUDIO, RFC2833.payloadType, "0-15");
+                }
+            }
+            String body = null;
+            sipCall.contenttypeH = "";
+            if (sipCall.sdp != null && sipCall.sdp.flag) {
+                sipCall.contenttypeH = "Content-Type: application/SDP\r\n";
+                if (SIPStack.bVideocommunication) {
+                    body = String.valueOf(sipCall.sdp.getBodyString()) + getVideomediadescription(sipCall.sdp.audioM.mediaPort + 2);
+                } else {
+                    body = sipCall.sdp.getBodyString();
+                }
+                sipCall.contentlengthH = "Content-Length: " + body.length();
+            } else {
+                body = "";
+                sipCall.contentlengthH = "Content-Length: 0";
+            }
+            sipCall.callState = 1;
+            sipCall.callDirection = SIPStack.SIP_CALLDIRECTION_OUT;
+            if (sipCall.authorizationINVITEH != null && sipCall.authorizationINVITEH.length() > 0) {
+                sipCall.message =
+                        String.valueOf(sipCall.commandLine) + SIPStack.SIP_LINE_END +
+                                sipCall.viaH + SIPStack.SIP_LINE_END +
+                                sipCall.maxforwardH + SIPStack.SIP_LINE_END +
+                                sipCall.contactH + SIPStack.SIP_LINE_END +
+                                sipCall.fromH + SIPStack.SIP_LINE_END +
+                                sipCall.toH + SIPStack.SIP_LINE_END +
+                                sipCall.callidH + SIPStack.SIP_LINE_END +
+                                sipCall.cseqH + SIPStack.SIP_LINE_END +
+                                sipCall.allowH + SIPStack.SIP_LINE_END +
+                                sipCall.useragentH + SIPStack.SIP_LINE_END +
+                                header +
+                                sipCall.authorizationINVITEH + SIPStack.SIP_LINE_END +
+                                sipCall.contenttypeH +
+                                sipCall.contentlengthH + SIPStack.SIP_LINE_DOUBLEEND +
+                                body;
+            } else {
+                sipCall.message =
+                        String.valueOf(sipCall.commandLine) + SIPStack.SIP_LINE_END +
+                                sipCall.viaH + SIPStack.SIP_LINE_END +
+                                sipCall.maxforwardH + SIPStack.SIP_LINE_END +
+                                sipCall.contactH + SIPStack.SIP_LINE_END +
+                                sipCall.fromH + SIPStack.SIP_LINE_END +
+                                sipCall.toH + SIPStack.SIP_LINE_END +
+                                sipCall.callidH + SIPStack.SIP_LINE_END +
+                                sipCall.cseqH + SIPStack.SIP_LINE_END +
+                                sipCall.allowH + SIPStack.SIP_LINE_END +
+                                sipCall.useragentH + SIPStack.SIP_LINE_END +
+                                header +
+                                sipCall.contenttypeH +
+                                sipCall.contentlengthH + SIPStack.SIP_LINE_DOUBLEEND +
+                                body;
+            }
+            return true;
+        } catch (Exception exception) {
+            return false;
+        }
+    }
+
+    public String makeRedirectIncomingCall(SIPCall sipCall, String redirectId) {
+        try {
+            if (sipCall == null || !sipCall.flag)
+                return "";
+            if (redirectId == null || redirectId.length() == 0)
+                return "";
+            if (sipCall.callDirection == SIPStack.SIP_CALLDIRECTION_IN)
+                if (sipCall.callState == 2 ||
+                        sipCall.callState == 12) {
+                    String commandLine = null;
+                    String contactH = null;
+                    String contentlengthH = null;
+                    commandLine = "SIP/2.0 302 " + SIPStack.getResponseDescription(302) + SIPStack.SIP_LINE_END;
+                    String viaString = "";
+                    if (sipCall.viaArray.length() > 0)
+                        viaString = sipCall.viaArray.toString();
+                    String routeString = "";
+                    if (sipCall.recordrouteArray.length() > 0)
+                        routeString = sipCall.recordrouteArray.toString();
+                    contactH = "Contact: <sip:" + redirectId + "@" + this.serverIp + ":" + this.serverPort + ">";
+                    contentlengthH = "Content-Length: 0" + SIPStack.SIP_LINE_END;
+                    String sendmessage =
+                            String.valueOf(commandLine) +
+                                    viaString +
+                                    routeString +
+                                    sipCall.fromH + SIPStack.SIP_LINE_END +
+                                    sipCall.toH + SIPStack.SIP_LINE_END +
+                                    sipCall.callidH + SIPStack.SIP_LINE_END +
+                                    sipCall.cseqH + SIPStack.SIP_LINE_END +
+                                    contactH + SIPStack.SIP_LINE_END +
+                                    contentlengthH + SIPStack.SIP_LINE_END;
+                    return sendmessage;
+                }
+        } catch (Exception exception) {}
+        return "";
+    }
+
+    public String makeSendProgressing(SIPCall sipCall, String body) {
+        try {
+            if (sipCall == null || !sipCall.flag)
+                return "";
+            if (body == null || body.length() <= 0)
+                return "";
+            String commandLine = null;
+            String contactH = null;
+            String contentlengthH = null;
+            commandLine = "SIP/2.0 183 " + SIPStack.getResponseDescription(183) + SIPStack.SIP_LINE_END;
+            String viaString = "";
+            if (sipCall.viaArray.length() > 0)
+                viaString = sipCall.viaArray.toString();
+            SIPHeader sipHeader = new SIPHeader(this.message, SIPStack.SIP_HEADERTYPE_VIA);
+            if (sipHeader != null && sipHeader.flag) {
+                this.viaH = String.valueOf(sipHeader.header) + SIPStack.SIP_LINE_END;
+            } else {
+                this.viaH = "";
+            }
+            String routeString = "";
+            if (sipCall.recordrouteArray != null &&
+                    sipCall.recordrouteArray.length() > 0)
+                routeString = sipCall.recordrouteArray.toString();
+            if (this.ifIp != null && this.ifIp.length() > 0 && this.ifPort > 0) {
+                contactH = "Contact: <sip:" + this.id + "@" + this.ifIp + ":" + this.ifPort + ">";
+            } else {
+                contactH = "Contact: <sip:" + this.id + "@" + sipCall.localIp + ":" + sipCall.localPort + ">";
+            }
+            contentlengthH = "Content-Length: " + body.length() + SIPStack.SIP_LINE_END;
+            String contenttypeH = "";
+            if (body != null && body.length() > 0)
+                contenttypeH = "Content-Type: application/SDP" + SIPStack.SIP_LINE_END;
+            String sendmessage =
+                    String.valueOf(commandLine) +
+                            viaString +
+                            routeString +
+                            sipCall.fromH + SIPStack.SIP_LINE_END +
+                            sipCall.toH + SIPStack.SIP_LINE_END +
+                            sipCall.callidH + SIPStack.SIP_LINE_END +
+                            sipCall.cseqH + SIPStack.SIP_LINE_END +
+                            contactH + SIPStack.SIP_LINE_END +
+                            contenttypeH +
+                            contentlengthH +
+                            SIPStack.SIP_LINE_END +
+                            body;
+            return sendmessage;
+        } catch (Exception exception) {
+            return "";
+        }
+    }
+
+    public boolean makeSendAck(SIPCall sipCall, String message) {
+        try {
+            sipCall.routeIp = "";
+            sipCall.routePort = 5060;
+            if (sipCall == null || !sipCall.flag)
+                return false;
+            sipCall.ACK_CSEQ = sipCall.CSEQ_NUMBER;
+            sipCall.reverseRecordRoute(message);
+            if (sipCall.remoteContactUri != null && sipCall.remoteContactUri.length() > 0) {
+                sipCall.commandLine = "ACK " + sipCall.remoteContactUri + " SIP/2.0";
+            } else {
+                sipCall.commandLine = "ACK sip:" + sipCall.dnis + "@" + this.serverDomain + ":" + this.serverPort + " SIP/2.0";
+            }
+            if (sipCall.viaH == null || sipCall.viaH.length() == 0) {
+                if (sipCall.viaBranch == null || sipCall.viaBranch.length() == 0)
+                    sipCall.viaBranch = SIPStack.getViaBranch();
+                sipCall.viaH = "Via: SIP/2.0/UDP " + this.localIp + ":" + this.localPort + ";branch=" + sipCall.viaBranch + ";rport";
+            }
+            sipCall.cseqH = "CSeq: " + sipCall.ACK_CSEQ + " ACK";
+            sipCall.contentlengthH = "Content-Length: 0";
+            if (this.ifIp != null && this.ifIp.length() > 0 && this.ifPort > 0) {
+                sipCall.contactH = "Contact: <sip:" + this.id + "@" + this.ifIp + ":" + this.ifPort + ">";
+            } else {
+                sipCall.contactH = "Contact: <sip:" + this.id + "@" + sipCall.localIp + ":" + sipCall.localPort + ">";
+            }
+            String routeString = "";
+            if (sipCall.routeArray != null &&
+                    sipCall.routeArray.length() > 0) {
+                routeString = sipCall.routeArray.toString();
+                if (sipCall.routeH != null && sipCall.routeH.length() > 0) {
+                    SIPROUTEHeader header = new SIPROUTEHeader(sipCall.routeH);
+                    if (header != null && header.flag) {
+                        sipCall.routeIp = header.getIp();
+                        sipCall.routePort = header.getPort();
+                    }
+                }
+            }
+            if (sipCall.authorizationACKH != null && sipCall.authorizationACKH.length() > 0) {
+                sipCall.message =
+                        String.valueOf(sipCall.commandLine) + SIPStack.SIP_LINE_END +
+                                sipCall.fromH + SIPStack.SIP_LINE_END +
+                                sipCall.toH + SIPStack.SIP_LINE_END +
+                                sipCall.viaH + SIPStack.SIP_LINE_END +
+                                routeString +
+                                sipCall.maxforwardH + SIPStack.SIP_LINE_END +
+                                sipCall.contactH + SIPStack.SIP_LINE_END +
+                                sipCall.callidH + SIPStack.SIP_LINE_END +
+                                sipCall.cseqH + SIPStack.SIP_LINE_END +
+                                sipCall.allowH + SIPStack.SIP_LINE_END +
+                                sipCall.useragentH + SIPStack.SIP_LINE_END +
+                                sipCall.authorizationACKH + SIPStack.SIP_LINE_END +
+                                sipCall.contentlengthH + SIPStack.SIP_LINE_DOUBLEEND;
+            } else {
+                sipCall.message =
+                        String.valueOf(sipCall.commandLine) + SIPStack.SIP_LINE_END +
+                                sipCall.fromH + SIPStack.SIP_LINE_END +
+                                sipCall.toH + SIPStack.SIP_LINE_END +
+                                sipCall.viaH + SIPStack.SIP_LINE_END +
+                                routeString +
+                                sipCall.maxforwardH + SIPStack.SIP_LINE_END +
+                                sipCall.contactH + SIPStack.SIP_LINE_END +
+                                sipCall.callidH + SIPStack.SIP_LINE_END +
+                                sipCall.cseqH + SIPStack.SIP_LINE_END +
+                                sipCall.allowH + SIPStack.SIP_LINE_END +
+                                sipCall.useragentH + SIPStack.SIP_LINE_END +
+                                sipCall.contentlengthH + SIPStack.SIP_LINE_DOUBLEEND;
+            }
+            return true;
+        } catch (Exception exception) {
+            return false;
+        }
+    }
+
+    public boolean makeSendFinalAck(SIPCall sipCall, String message) {
+        try {
+            String fromH = null;
+            String toH = null;
+            String callidH = null;
+            String viaH = null;
+            String commandLine = null;
+            String contentlengthH = null;
+            String cseqH = null;
+            SIPHeader sipheader = null;
+            sipCall.routeIp = "";
+            sipCall.routePort = 5060;
+            if (sipCall == null || !sipCall.flag)
+                return false;
+            sipheader = new SIPHeader(message, SIPStack.SIP_HEADERTYPE_FROM);
+            if (sipheader != null && sipheader.flag && sipheader.header != null && sipheader.header.length() > 0) {
+                fromH = new String(sipheader.header);
+            } else {
+                return false;
+            }
+            sipheader = new SIPHeader(message, SIPStack.SIP_HEADERTYPE_TO);
+            if (sipheader != null && sipheader.flag && sipheader.header != null && sipheader.header.length() > 0) {
+                toH = new String(sipheader.header);
+            } else {
+                return false;
+            }
+            sipheader = new SIPHeader(message, SIPStack.SIP_HEADERTYPE_CALLID);
+            if (sipheader != null && sipheader.flag && sipheader.header != null && sipheader.header.length() > 0) {
+                callidH = new String(sipheader.header);
+            } else {
+                return false;
+            }
+            int ACK_CSEQ = sipCall.CSEQ_NUMBER;
+            sipheader = new SIPHeader(message, SIPStack.SIP_HEADERTYPE_CSEQ);
+            if (sipheader != null && sipheader.flag && sipheader.callSequenceNumber() >= 0)
+                ACK_CSEQ = sipheader.callSequenceNumber();
+            sipCall.reverseRecordRoute(message);
+            if (sipCall.remoteContactUri != null && sipCall.remoteContactUri.length() > 0) {
+                commandLine = "ACK " + sipCall.remoteContactUri + " SIP/2.0";
+            } else {
+                commandLine = "ACK sip:" + sipCall.dnis + "@" + this.serverDomain + ":" + this.serverPort + " SIP/2.0";
+            }
+            sipheader = new SIPHeader(message, SIPStack.SIP_HEADERTYPE_VIA);
+            if (sipheader != null && sipheader.flag) {
+                viaH = new String(sipheader.header);
+                if (viaH != null && viaH.length() > 0) {
+                    String branch = "";
+                    int index = viaH.indexOf(";branch=");
+                    if (index > 0)
+                        branch = viaH.substring(index + 1);
+                    index = branch.indexOf(";");
+                    if (index > 0)
+                        branch = branch.substring(0, index);
+                    index = viaH.indexOf(";received=");
+                    if (index > 0)
+                        viaH = viaH.substring(0, index);
+                    index = viaH.indexOf(";rport=");
+                    if (index > 0)
+                        viaH = viaH.substring(0, index);
+                    viaH = String.valueOf(viaH) + ";" + branch;
+                }
+            }
+            if (viaH == null || viaH.length() == 0)
+                viaH = "Via: SIP/2.0/UDP " + this.localIp + ":" + this.localPort + ";branch=" + SIPStack.getViaBranch() + ";rport";
+            cseqH = "CSeq: " + ACK_CSEQ + " ACK";
+            contentlengthH = "Content-Length: 0";
+            String routeString = "";
+            if (sipCall.routeArray != null &&
+                    sipCall.routeArray.length() > 0) {
+                routeString = sipCall.routeArray.toString();
+                if (sipCall.routeH != null && sipCall.routeH.length() > 0) {
+                    SIPROUTEHeader header = new SIPROUTEHeader(sipCall.routeH);
+                    if (header != null && header.flag) {
+                        sipCall.routeIp = header.getIp();
+                        sipCall.routePort = header.getPort();
+                    }
+                }
+            }
+            if (sipCall.authorizationACKH != null && sipCall.authorizationACKH.length() > 0) {
+                sipCall.message =
+                        String.valueOf(commandLine) + SIPStack.SIP_LINE_END +
+                                fromH + SIPStack.SIP_LINE_END +
+                                toH + SIPStack.SIP_LINE_END +
+                                viaH + SIPStack.SIP_LINE_END +
+                                routeString +
+                                callidH + SIPStack.SIP_LINE_END +
+                                cseqH + SIPStack.SIP_LINE_END +
+                                sipCall.authorizationACKH + SIPStack.SIP_LINE_END +
+                                contentlengthH + SIPStack.SIP_LINE_DOUBLEEND;
+            } else {
+                sipCall.message =
+                        String.valueOf(commandLine) + SIPStack.SIP_LINE_END +
+                                fromH + SIPStack.SIP_LINE_END +
+                                toH + SIPStack.SIP_LINE_END +
+                                viaH + SIPStack.SIP_LINE_END +
+                                routeString +
+                                callidH + SIPStack.SIP_LINE_END +
+                                cseqH + SIPStack.SIP_LINE_END +
+                                contentlengthH + SIPStack.SIP_LINE_DOUBLEEND;
+            }
+            return true;
+        } catch (Exception exception) {
+            return false;
+        }
+    }
+
+    public String makeSendFinalAck(SIPCall sipCall, String message, String remoteIp, int remotePort) {
+        try {
+            String fromH = null;
+            String toH = null;
+            String callidH = null;
+            String viaH = null;
+            String commandLine = null;
+            String contentlengthH = null;
+            String cseqH = null;
+            SIPHeader sipheader = null;
+            sipheader = new SIPHeader(message, SIPStack.SIP_HEADERTYPE_FROM);
+            if (sipheader != null && sipheader.flag && sipheader.header != null && sipheader.header.length() > 0) {
+                fromH = new String(sipheader.header);
+            } else {
+                return "";
+            }
+            sipheader = new SIPHeader(message, SIPStack.SIP_HEADERTYPE_TO);
+            if (sipheader != null && sipheader.flag && sipheader.header != null && sipheader.header.length() > 0) {
+                toH = new String(sipheader.header);
+            } else {
+                return "";
+            }
+            sipheader = new SIPHeader(message, SIPStack.SIP_HEADERTYPE_CALLID);
+            if (sipheader != null && sipheader.flag && sipheader.header != null && sipheader.header.length() > 0) {
+                callidH = new String(sipheader.header);
+            } else {
+                return "";
+            }
+            int ACK_CSEQ = 0;
+            sipheader = new SIPHeader(message, SIPStack.SIP_HEADERTYPE_CSEQ);
+            if (sipheader != null && sipheader.flag && sipheader.callSequenceNumber() >= 0)
+                ACK_CSEQ = sipheader.callSequenceNumber();
+            commandLine = "ACK sip:" + sipCall.dnis + "@" + this.serverDomain + ":" + this.serverPort + " SIP/2.0";
+            sipheader = new SIPHeader(message, SIPStack.SIP_HEADERTYPE_VIA);
+            if (sipheader != null && sipheader.flag) {
+                viaH = new String(sipheader.header);
+                if (viaH != null && viaH.length() > 0) {
+                    String branch = "";
+                    int index = viaH.indexOf(";branch=");
+                    if (index > 0)
+                        branch = viaH.substring(index + 1);
+                    index = branch.indexOf(";");
+                    if (index > 0)
+                        branch = branch.substring(0, index);
+                    index = viaH.indexOf(";received=");
+                    if (index > 0)
+                        viaH = viaH.substring(0, index);
+                    index = viaH.indexOf(";rport=");
+                    if (index > 0)
+                        viaH = viaH.substring(0, index);
+                    viaH = String.valueOf(viaH) + ";" + branch;
+                }
+            }
+            if (viaH == null || viaH.length() == 0)
+                viaH = "Via: SIP/2.0/UDP " + this.localIp + ":" + this.localPort + ";branch=" + SIPStack.getViaBranch() + ";rport";
+            cseqH = "CSeq: " + ACK_CSEQ + " ACK";
+            contentlengthH = "Content-Length: 0";
+            String sendmessage =
+                    String.valueOf(commandLine) + SIPStack.SIP_LINE_END +
+                            fromH + SIPStack.SIP_LINE_END +
+                            toH + SIPStack.SIP_LINE_END +
+                            viaH + SIPStack.SIP_LINE_END +
+                            callidH + SIPStack.SIP_LINE_END +
+                            cseqH + SIPStack.SIP_LINE_END +
+                            contentlengthH + SIPStack.SIP_LINE_DOUBLEEND;
+            return sendmessage;
+        } catch (Exception exception) {
+            return "";
+        }
+    }
+
+    public boolean makeSendRedirectFinalAck(SIPCall sipCall, String message) {
+        try {
+            sipCall.routeIp = "";
+            sipCall.routePort = 5060;
+            if (sipCall == null || !sipCall.flag)
+                return false;
+            sipCall.ACK_CSEQ = sipCall.CSEQ_NUMBER;
+            sipCall.reverseRecordRoute(message);
+            sipCall.commandLine = "ACK sip:" + sipCall.dnis + "@" + this.serverDomain + ":" + this.serverPort + " SIP/2.0";
+            if (sipCall.viaH == null || sipCall.viaH.length() == 0) {
+                if (sipCall.viaBranch == null || sipCall.viaBranch.length() == 0)
+                    sipCall.viaBranch = SIPStack.getViaBranch();
+                sipCall.viaH = "Via: SIP/2.0/UDP " + this.localIp + ":" + this.localPort + ";branch=" + sipCall.viaBranch + ";rport";
+            }
+            sipCall.cseqH = "CSeq: " + sipCall.ACK_CSEQ + " ACK";
+            sipCall.contentlengthH = "Content-Length: 0";
+            if (this.ifIp != null && this.ifIp.length() > 0 && this.ifPort > 0) {
+                sipCall.contactH = "Contact: <sip:" + this.id + "@" + this.ifIp + ":" + this.ifPort + ">";
+            } else {
+                sipCall.contactH = "Contact: <sip:" + this.id + "@" + sipCall.localIp + ":" + sipCall.localPort + ">";
+            }
+            String routeString = "";
+            if (sipCall.routeArray != null &&
+                    sipCall.routeArray.length() > 0) {
+                routeString = sipCall.routeArray.toString();
+                if (sipCall.routeH != null && sipCall.routeH.length() > 0) {
+                    SIPROUTEHeader header = new SIPROUTEHeader(sipCall.routeH);
+                    if (header != null && header.flag) {
+                        sipCall.routeIp = header.getIp();
+                        sipCall.routePort = header.getPort();
+                    }
+                }
+            }
+            if (sipCall.authorizationACKH != null && sipCall.authorizationACKH.length() > 0) {
+                sipCall.message =
+                        String.valueOf(sipCall.commandLine) + SIPStack.SIP_LINE_END +
+                                sipCall.fromH + SIPStack.SIP_LINE_END +
+                                sipCall.toH + SIPStack.SIP_LINE_END +
+                                sipCall.viaH + SIPStack.SIP_LINE_END +
+                                routeString +
+                                sipCall.maxforwardH + SIPStack.SIP_LINE_END +
+                                sipCall.contactH + SIPStack.SIP_LINE_END +
+                                sipCall.callidH + SIPStack.SIP_LINE_END +
+                                sipCall.cseqH + SIPStack.SIP_LINE_END +
+                                sipCall.allowH + SIPStack.SIP_LINE_END +
+                                sipCall.useragentH + SIPStack.SIP_LINE_END +
+                                sipCall.authorizationACKH + SIPStack.SIP_LINE_END +
+                                sipCall.contentlengthH + SIPStack.SIP_LINE_DOUBLEEND;
+            } else {
+                sipCall.message =
+                        String.valueOf(sipCall.commandLine) + SIPStack.SIP_LINE_END +
+                                sipCall.fromH + SIPStack.SIP_LINE_END +
+                                sipCall.toH + SIPStack.SIP_LINE_END +
+                                sipCall.viaH + SIPStack.SIP_LINE_END +
+                                routeString +
+                                sipCall.maxforwardH + SIPStack.SIP_LINE_END +
+                                sipCall.contactH + SIPStack.SIP_LINE_END +
+                                sipCall.callidH + SIPStack.SIP_LINE_END +
+                                sipCall.cseqH + SIPStack.SIP_LINE_END +
+                                sipCall.allowH + SIPStack.SIP_LINE_END +
+                                sipCall.useragentH + SIPStack.SIP_LINE_END +
+                                sipCall.contentlengthH + SIPStack.SIP_LINE_DOUBLEEND;
+            }
+            return true;
+        } catch (Exception exception) {
+            return false;
+        }
+    }
+
+    public String makeSendByeResponse(SIPCall sipCall, String message) {
+        try {
+            if (sipCall == null || !sipCall.flag)
+                return "";
+            sipCall.BYE_CSEQ = sipCall.ACK_CSEQ;
+            String commandLine = null;
+            String viaH = null;
+            String toH = null;
+            String fromH = null;
+            String callidH = null;
+            String cseqH = null;
+            String contentlengthH = null;
+            commandLine = "SIP/2.0 200 " + SIPStack.getResponseDescription(200) + SIPStack.SIP_LINE_END;
+            viaH = sipCall.getViaArray(message);
+            if (viaH == null || viaH.length() == 0)
+                viaH = "";
+            SIPHeader sipHeader = new SIPHeader(message, SIPStack.SIP_HEADERTYPE_FROM);
+            if (sipHeader != null && sipHeader.flag) {
+                fromH = String.valueOf(sipHeader.header) + SIPStack.SIP_LINE_END;
+            } else {
+                fromH = "";
+            }
+            sipHeader = new SIPHeader(message, SIPStack.SIP_HEADERTYPE_TO);
+            if (sipHeader != null && sipHeader.flag) {
+                toH = String.valueOf(sipHeader.header) + SIPStack.SIP_LINE_END;
+                if (toH.indexOf("tag=") < 0)
+                    toH = String.valueOf(sipHeader.header) + ";tag=" + SIPStack.newTag() + SIPStack.SIP_LINE_END;
+            } else {
+                toH = "";
+            }
+            sipHeader = new SIPHeader(message, SIPStack.SIP_HEADERTYPE_CALLID);
+            if (sipHeader != null && sipHeader.flag) {
+                callidH = String.valueOf(sipHeader.header) + SIPStack.SIP_LINE_END;
+            } else {
+                callidH = "";
+            }
+            sipHeader = new SIPHeader(message, SIPStack.SIP_HEADERTYPE_CSEQ);
+            if (sipHeader != null && sipHeader.flag) {
+                sipCall.BYE_CSEQ = sipHeader.callSequenceNumber();
+                cseqH = String.valueOf(sipHeader.header) + SIPStack.SIP_LINE_END;
+            } else {
+                cseqH = "";
+            }
+            contentlengthH = "Content-Length: 0\r\n";
+            String sendmessage =
+                    String.valueOf(commandLine) +
+                            viaH +
+                            fromH +
+                            toH +
+                            callidH +
+                            cseqH +
+                            contentlengthH + SIPStack.SIP_LINE_END;
+            return sendmessage;
+        } catch (Exception exception) {
+            return "";
+        }
+    }
+
+    public String makeSendOptionsResponse(SIPCall sipCall, String message, int code) {
+        try {
+            if (sipCall == null || !sipCall.flag)
+                return "";
+            String commandLine = null;
+            String viaH = null;
+            String toH = null;
+            String fromH = null;
+            String callidH = null;
+            String cseqH = null;
+            String allowH = null;
+            String useragentH = null;
+            String contentlengthH = null;
+            commandLine = "SIP/2.0 " + code + " " + SIPStack.getResponseDescription(code) + SIPStack.SIP_LINE_END;
+            viaH = sipCall.getViaArray(message);
+            if (viaH == null || viaH.length() == 0)
+                viaH = "";
+            SIPHeader sipHeader = new SIPHeader(message, SIPStack.SIP_HEADERTYPE_FROM);
+            if (sipHeader != null && sipHeader.flag) {
+                fromH = String.valueOf(sipHeader.header) + SIPStack.SIP_LINE_END;
+            } else {
+                fromH = "";
+            }
+            sipHeader = new SIPHeader(message, SIPStack.SIP_HEADERTYPE_TO);
+            if (sipHeader != null && sipHeader.flag) {
+                toH = String.valueOf(sipHeader.header) + SIPStack.SIP_LINE_END;
+                if (toH.indexOf("tag=") < 0)
+                    toH = String.valueOf(sipHeader.header) + ";tag=" + SIPStack.newTag() + SIPStack.SIP_LINE_END;
+            } else {
+                toH = "";
+            }
+            sipHeader = new SIPHeader(message, SIPStack.SIP_HEADERTYPE_CALLID);
+            if (sipHeader != null && sipHeader.flag) {
+                callidH = String.valueOf(sipHeader.header) + SIPStack.SIP_LINE_END;
+            } else {
+                callidH = "";
+            }
+            sipHeader = new SIPHeader(message, SIPStack.SIP_HEADERTYPE_CSEQ);
+            if (sipHeader != null && sipHeader.flag) {
+                cseqH = String.valueOf(sipHeader.header) + SIPStack.SIP_LINE_END;
+            } else {
+                cseqH = "";
+            }
+            allowH = "Allow: INVITE, ACK, CANCEL, OPTIONS, BYE, REFER, NOTIFY, MESSAGE, SUBSCRIBE, INFO" + SIPStack.SIP_LINE_END;
+            useragentH = "User-Agent: KwangHaeSoft SmartSip release 0100o" + SIPStack.SIP_LINE_END;
+            contentlengthH = "Content-Length: 0\r\n";
+            String sendmessage =
+                    String.valueOf(commandLine) +
+                            viaH +
+                            fromH +
+                            toH +
+                            callidH +
+                            cseqH +
+                            allowH +
+                            useragentH +
+                            contentlengthH + SIPStack.SIP_LINE_END;
+            return sendmessage;
+        } catch (Exception exception) {
+            return "";
+        }
+    }
+
+    public String makeSendInfoResponse(SIPCall sipCall, String message, int code) {
+        if (sipCall == null || !sipCall.flag)
+            return "";
+        try {
+            String commandLine = null;
+            String viaH = null;
+            String toH = null;
+            String fromH = null;
+            String callidH = null;
+            String cseqH = null;
+            String allowH = null;
+            String useragentH = null;
+            String contentlengthH = null;
+            commandLine = "SIP/2.0 " + code + " " + SIPStack.getResponseDescription(code) + SIPStack.SIP_LINE_END;
+            viaH = sipCall.getViaArray(message);
+            if (viaH == null || viaH.length() == 0)
+                viaH = "";
+            SIPHeader sipHeader = new SIPHeader(message, SIPStack.SIP_HEADERTYPE_FROM);
+            if (sipHeader != null && sipHeader.flag) {
+                fromH = String.valueOf(sipHeader.header) + SIPStack.SIP_LINE_END;
+            } else {
+                fromH = "";
+            }
+            sipHeader = new SIPHeader(message, SIPStack.SIP_HEADERTYPE_TO);
+            if (sipHeader != null && sipHeader.flag) {
+                toH = String.valueOf(sipHeader.header) + SIPStack.SIP_LINE_END;
+                if (toH.indexOf("tag=") < 0)
+                    toH = String.valueOf(sipHeader.header) + ";tag=" + SIPStack.newTag() + SIPStack.SIP_LINE_END;
+            } else {
+                toH = "";
+            }
+            sipHeader = new SIPHeader(message, SIPStack.SIP_HEADERTYPE_CALLID);
+            if (sipHeader != null && sipHeader.flag) {
+                callidH = String.valueOf(sipHeader.header) + SIPStack.SIP_LINE_END;
+            } else {
+                callidH = "";
+            }
+            sipHeader = new SIPHeader(message, SIPStack.SIP_HEADERTYPE_CSEQ);
+            if (sipHeader != null && sipHeader.flag) {
+                cseqH = String.valueOf(sipHeader.header) + SIPStack.SIP_LINE_END;
+            } else {
+                cseqH = "";
+            }
+            if (this.ifIp != null && this.ifIp.length() > 0 && this.ifPort > 0) {
+                this.contactH = "Contact: <sip:" + this.id + "@" + this.ifIp + ":" + this.ifPort + ">" + SIPStack.SIP_LINE_END;
+            } else {
+                this.contactH = "Contact: <sip:" + this.id + "@" + sipCall.localIp + ":" + sipCall.localPort + ">" + SIPStack.SIP_LINE_END;
+            }
+            allowH = "Allow: INVITE, ACK, CANCEL, OPTIONS, BYE, REFER, NOTIFY, MESSAGE, SUBSCRIBE, INFO" + SIPStack.SIP_LINE_END;
+            useragentH = "User-Agent: KwangHaeSoft SmartSip release 0100o" + SIPStack.SIP_LINE_END;
+            contentlengthH = "Content-Length: 0\r\n";
+            String sendmessage =
+                    String.valueOf(commandLine) +
+                            viaH +
+                            fromH +
+                            toH +
+                            callidH +
+                            cseqH +
+                            this.contactH +
+                            allowH +
+                            useragentH +
+                            contentlengthH + SIPStack.SIP_LINE_END;
+            return sendmessage;
+        } catch (Exception exception) {
+            return "";
+        }
+    }
+
+    public boolean makeSendUpdate(SIPCall sipCall) {
+        try {
+            if (sipCall == null || !sipCall.flag)
+                return false;
+            String viaBranch = sipCall.viaBranch;
+            sipCall.setUpdateheaders("sendonly");
+            sipCall.CSEQ_NUMBER = SIPStack.SIP_SEQUENCE_INVITE;
+            SIPStack.SIP_SEQUENCE_INVITE++;
+            if (SIPStack.SIP_SEQUENCE_INVITE > 65556)
+                SIPStack.SIP_SEQUENCE_INVITE = 1;
+            sipCall.commandLine = "INVITE sip:" + sipCall.dnis + "@" + this.serverDomain + ":" + this.serverPort + " SIP/2.0";
+            sipCall.viaBranch = viaBranch;
+            if (sipCall.viaBranch == null || sipCall.viaBranch.length() == 0)
+                sipCall.viaBranch = SIPStack.getViaBranch();
+            sipCall.viaH = "Via: SIP/2.0/UDP " + this.localIp + ":" + this.localPort + ";branch=" + sipCall.viaBranch + ";rport";
+            sipCall.maxforwardH = "Max-Forwards: 70";
+            if (this.ifIp != null && this.ifIp.length() > 0 && this.ifPort > 0) {
+                sipCall.contactH = "Contact: <sip:" + this.id + "@" + this.ifIp + ":" + this.ifPort + ">";
+            } else {
+                sipCall.contactH = "Contact: <sip:" + this.id + "@" + sipCall.localIp + ":" + sipCall.localPort + ">";
+            }
+            if (sipCall.toH == null || sipCall.toH.length() == 0)
+                sipCall.toH = "To: \"" + sipCall.dnis + "\"<sip:" + sipCall.dnis + "@" + sipCall.serverDomain + ":" + sipCall.serverPort + ">";
+            if (sipCall.fromH == null || sipCall.fromH.length() == 0) {
+                sipCall.fromTag = SIPStack.newTag();
+                sipCall.fromH = "From: \"" + sipCall.id + "\"<sip:" + sipCall.id + "@" + sipCall.serverDomain + ":" + sipCall.serverPort + ">;tag=" + sipCall.fromTag;
+            }
+            sipCall.cseqH = "CSeq: " + sipCall.CSEQ_NUMBER + " INVITE";
+            sipCall.allowH = "Allow: INVITE, ACK, CANCEL, OPTIONS, BYE, REFER, NOTIFY, MESSAGE, SUBSCRIBE, INFO";
+            sipCall.useragentH = "User-Agent: " + SIPStack.USER_AGENT;
+            if (sipCall.sdp == null) {
+                int audioport = SIPStack.getFreeAudioRtpPort();
+                if (audioport > 0)
+                    sipCall.constructSdp();
+                if (sipCall.sdp != null && sipCall.sdp.flag) {
+                    sipCall.sdp.setMediaPort(SIPStack.SIP_MEDIATYPE_AUDIO, audioport);
+                    if (SIPStack.PRIMARY_CODEC_AUDIO == SIPStack.SIP_CODEC_G711U) {
+                        sipCall.sdp.setCodec(
+                                SIPStack.SIP_MEDIATYPE_AUDIO,
+                                SIPStack.SIP_CODEC_G711U,
+                                "PCMU/8000");
+                        sipCall.sdp.setCodec(
+                                SIPStack.SIP_MEDIATYPE_AUDIO,
+                                SIPStack.SIP_CODEC_G711A,
+                                "PCMA/8000");
+                    } else {
+                        sipCall.sdp.setCodec(
+                                SIPStack.SIP_MEDIATYPE_AUDIO,
+                                SIPStack.SIP_CODEC_G711A,
+                                "PCMA/8000");
+                        sipCall.sdp.setCodec(
+                                SIPStack.SIP_MEDIATYPE_AUDIO,
+                                SIPStack.SIP_CODEC_G711U,
+                                "PCMU/8000");
+                    }
+                    sipCall.sdp.setCodec(
+                            SIPStack.SIP_MEDIATYPE_AUDIO,
+                            RFC2833.payloadType,
+                            "telephone-event/8000");
+                    sipCall.sdp.setFmtpDescribe(SIPStack.SIP_MEDIATYPE_AUDIO, RFC2833.payloadType, "0-15");
+                }
+            }
+            String body = null;
+            sipCall.contenttypeH = "";
+            if (sipCall.sdp != null && sipCall.sdp.flag) {
+                sipCall.contenttypeH = "Content-Type: application/SDP\r\n";
+                if (SIPStack.bVideocommunication) {
+                    body = String.valueOf(sipCall.sdp.getBodyString()) + getVideomediadescription(sipCall.sdp.audioM.mediaPort + 2);
+                } else {
+                    body = sipCall.sdp.getBodyString();
+                }
+                sipCall.contentlengthH = "Content-Length: " + body.length();
+            } else {
+                body = "";
+                sipCall.contentlengthH = "Content-Length: 0";
+            }
+            sipCall.callState = 20;
+            sipCall.callDirection = SIPStack.SIP_CALLDIRECTION_OUT;
+            if (sipCall.authorizationINVITEH != null && sipCall.authorizationINVITEH.length() > 0) {
+                sipCall.message =
+                        String.valueOf(sipCall.commandLine) + SIPStack.SIP_LINE_END +
+                                sipCall.viaH + SIPStack.SIP_LINE_END +
+                                sipCall.maxforwardH + SIPStack.SIP_LINE_END +
+                                sipCall.contactH + SIPStack.SIP_LINE_END +
+                                sipCall.fromH + SIPStack.SIP_LINE_END +
+                                sipCall.toH + SIPStack.SIP_LINE_END +
+                                sipCall.callidH + SIPStack.SIP_LINE_END +
+                                sipCall.cseqH + SIPStack.SIP_LINE_END +
+                                sipCall.allowH + SIPStack.SIP_LINE_END +
+                                sipCall.useragentH + SIPStack.SIP_LINE_END +
+                                sipCall.authorizationINVITEH + SIPStack.SIP_LINE_END +
+                                sipCall.contenttypeH +
+                                sipCall.contentlengthH + SIPStack.SIP_LINE_DOUBLEEND +
+                                body;
+            } else {
+                sipCall.message =
+                        String.valueOf(sipCall.commandLine) + SIPStack.SIP_LINE_END +
+                                sipCall.viaH + SIPStack.SIP_LINE_END +
+                                sipCall.maxforwardH + SIPStack.SIP_LINE_END +
+                                sipCall.contactH + SIPStack.SIP_LINE_END +
+                                sipCall.fromH + SIPStack.SIP_LINE_END +
+                                sipCall.toH + SIPStack.SIP_LINE_END +
+                                sipCall.callidH + SIPStack.SIP_LINE_END +
+                                sipCall.cseqH + SIPStack.SIP_LINE_END +
+                                sipCall.allowH + SIPStack.SIP_LINE_END +
+                                sipCall.useragentH + SIPStack.SIP_LINE_END +
+                                sipCall.contenttypeH +
+                                sipCall.contentlengthH + SIPStack.SIP_LINE_DOUBLEEND +
+                                body;
+            }
+            return true;
+        } catch (Exception exception) {
+            return false;
+        }
+    }
+
+    public boolean makeSendUpdate(SIPCall sipCall, String flow) {
+        try {
+            if (sipCall == null || !sipCall.flag)
+                return false;
+            String viaBranch = sipCall.viaBranch;
+            sipCall.setUpdateheaders(flow);
+            sipCall.CSEQ_NUMBER = SIPStack.SIP_SEQUENCE_INVITE;
+            SIPStack.SIP_SEQUENCE_INVITE++;
+            if (SIPStack.SIP_SEQUENCE_INVITE > 65556)
+                SIPStack.SIP_SEQUENCE_INVITE = 1;
+            sipCall.commandLine = "INVITE sip:" + sipCall.dnis + "@" + this.serverDomain + ":" + this.serverPort + " SIP/2.0";
+            sipCall.viaBranch = viaBranch;
+            if (sipCall.viaBranch == null || sipCall.viaBranch.length() == 0)
+                sipCall.viaBranch = SIPStack.getViaBranch();
+            sipCall.viaH = "Via: SIP/2.0/UDP " + this.localIp + ":" + this.localPort + ";branch=" + sipCall.viaBranch + ";rport";
+            sipCall.maxforwardH = "Max-Forwards: 70";
+            if (this.ifIp != null && this.ifIp.length() > 0 && this.ifPort > 0) {
+                sipCall.contactH = "Contact: <sip:" + this.id + "@" + this.ifIp + ":" + this.ifPort + ">";
+            } else {
+                sipCall.contactH = "Contact: <sip:" + this.id + "@" + sipCall.localIp + ":" + sipCall.localPort + ">";
+            }
+            if (sipCall.toH == null || sipCall.toH.length() == 0)
+                sipCall.toH = "To: \"" + sipCall.dnis + "\"<sip:" + sipCall.dnis + "@" + sipCall.serverDomain + ":" + sipCall.serverPort + ">";
+            if (sipCall.fromH == null || sipCall.fromH.length() == 0) {
+                sipCall.fromTag = SIPStack.newTag();
+                sipCall.fromH = "From: \"" + sipCall.id + "\"<sip:" + sipCall.id + "@" + sipCall.serverDomain + ":" + sipCall.serverPort + ">;tag=" + sipCall.fromTag;
+            }
+            sipCall.cseqH = "CSeq: " + sipCall.CSEQ_NUMBER + " INVITE";
+            sipCall.allowH = "Allow: INVITE, ACK, CANCEL, OPTIONS, BYE, REFER, NOTIFY, MESSAGE, SUBSCRIBE, INFO";
+            sipCall.useragentH = "User-Agent: " + SIPStack.USER_AGENT;
+            if (sipCall.sdp == null) {
+                int audioport = SIPStack.getFreeAudioRtpPort();
+                if (audioport > 0)
+                    sipCall.constructSdp();
+                if (sipCall.sdp != null && sipCall.sdp.flag) {
+                    sipCall.sdp.setMediaPort(SIPStack.SIP_MEDIATYPE_AUDIO, audioport);
+                    if (SIPStack.PRIMARY_CODEC_AUDIO == SIPStack.SIP_CODEC_G711U) {
+                        sipCall.sdp.setCodec(
+                                SIPStack.SIP_MEDIATYPE_AUDIO,
+                                SIPStack.SIP_CODEC_G711U,
+                                "PCMU/8000");
+                        sipCall.sdp.setCodec(
+                                SIPStack.SIP_MEDIATYPE_AUDIO,
+                                SIPStack.SIP_CODEC_G711A,
+                                "PCMA/8000");
+                    } else {
+                        sipCall.sdp.setCodec(
+                                SIPStack.SIP_MEDIATYPE_AUDIO,
+                                SIPStack.SIP_CODEC_G711A,
+                                "PCMA/8000");
+                        sipCall.sdp.setCodec(
+                                SIPStack.SIP_MEDIATYPE_AUDIO,
+                                SIPStack.SIP_CODEC_G711U,
+                                "PCMU/8000");
+                    }
+                    sipCall.sdp.setCodec(
+                            SIPStack.SIP_MEDIATYPE_AUDIO,
+                            RFC2833.payloadType,
+                            "telephone-event/8000");
+                    sipCall.sdp.setFmtpDescribe(SIPStack.SIP_MEDIATYPE_AUDIO, RFC2833.payloadType, "0-15");
+                }
+            }
+            String body = null;
+            sipCall.contenttypeH = "";
+            if (sipCall.sdp != null && sipCall.sdp.flag) {
+                sipCall.contenttypeH = "Content-Type: application/SDP\r\n";
+                if (SIPStack.bVideocommunication) {
+                    body = String.valueOf(sipCall.sdp.getBodyString()) + getVideomediadescription(sipCall.sdp.audioM.mediaPort + 2);
+                } else {
+                    body = sipCall.sdp.getBodyString();
+                }
+                sipCall.contentlengthH = "Content-Length: " + body.length();
+            } else {
+                body = "";
+                sipCall.contentlengthH = "Content-Length: 0";
+            }
+            sipCall.callState = 20;
+            sipCall.callDirection = SIPStack.SIP_CALLDIRECTION_OUT;
+            if (sipCall.authorizationINVITEH != null && sipCall.authorizationINVITEH.length() > 0) {
+                sipCall.message =
+                        String.valueOf(sipCall.commandLine) + SIPStack.SIP_LINE_END +
+                                sipCall.viaH + SIPStack.SIP_LINE_END +
+                                sipCall.maxforwardH + SIPStack.SIP_LINE_END +
+                                sipCall.contactH + SIPStack.SIP_LINE_END +
+                                sipCall.fromH + SIPStack.SIP_LINE_END +
+                                sipCall.toH + SIPStack.SIP_LINE_END +
+                                sipCall.callidH + SIPStack.SIP_LINE_END +
+                                sipCall.cseqH + SIPStack.SIP_LINE_END +
+                                sipCall.allowH + SIPStack.SIP_LINE_END +
+                                sipCall.useragentH + SIPStack.SIP_LINE_END +
+                                sipCall.authorizationINVITEH + SIPStack.SIP_LINE_END +
+                                sipCall.contenttypeH +
+                                sipCall.contentlengthH + SIPStack.SIP_LINE_DOUBLEEND +
+                                body;
+            } else {
+                sipCall.message =
+                        String.valueOf(sipCall.commandLine) + SIPStack.SIP_LINE_END +
+                                sipCall.viaH + SIPStack.SIP_LINE_END +
+                                sipCall.maxforwardH + SIPStack.SIP_LINE_END +
+                                sipCall.contactH + SIPStack.SIP_LINE_END +
+                                sipCall.fromH + SIPStack.SIP_LINE_END +
+                                sipCall.toH + SIPStack.SIP_LINE_END +
+                                sipCall.callidH + SIPStack.SIP_LINE_END +
+                                sipCall.cseqH + SIPStack.SIP_LINE_END +
+                                sipCall.allowH + SIPStack.SIP_LINE_END +
+                                sipCall.useragentH + SIPStack.SIP_LINE_END +
+                                sipCall.contenttypeH +
+                                sipCall.contentlengthH + SIPStack.SIP_LINE_DOUBLEEND +
+                                body;
+            }
+            return true;
+        } catch (Exception exception) {
+            return false;
+        }
+    }
+
+    public static String getCallfailReason(int finalCode) {
+        String desc = "";
+        switch (finalCode) {
+            case 200:
+                desc = "통화";
+                break;
+            case 300:
+                desc = "거절";
+                break;
+            case 301:
+                desc = "거절";
+                break;
+            case 302:
+                desc = "거절";
+                break;
+            case 305:
+                desc = "거절";
+                break;
+            case 380:
+                desc = "거절";
+                break;
+            case 400:
+                desc = "거절";
+                break;
+            case 401:
+                desc = "거절";
+                break;
+            case 402:
+                desc = "거절";
+                break;
+            case 403:
+                desc = "거절";
+                break;
+            case 404:
+                desc = "거절";
+                break;
+            case 405:
+                desc = "거절";
+                break;
+            case 406:
+                desc = "거절";
+                break;
+            case 407:
+                desc = "거절";
+                break;
+            case 408:
+                desc = "거절";
+                break;
+            case 409:
+                desc = "거절";
+                break;
+            case 410:
+                desc = "거절";
+                break;
+            case 411:
+                desc = "거절";
+                break;
+            case 413:
+                desc = "거절";
+                break;
+            case 414:
+                desc = "거절";
+                break;
+            case 415:
+                desc = "거절";
+                break;
+            case 420:
+                desc = "거절";
+                break;
+            case 421:
+                desc = "거절";
+                break;
+            case 423:
+                desc = "거절";
+                break;
+            case 480:
+                desc = "거절";
+                break;
+            case 481:
+                desc = "거절";
+                break;
+            case 482:
+                desc = "거절";
+                break;
+            case 483:
+                desc = "거절";
+                break;
+            case 484:
+                desc = "거절";
+                break;
+            case 485:
+                desc = "거절";
+                break;
+            case 486:
+                desc = "거절";
+                break;
+            case 487:
+                desc = "통화중";
+                break;
+            case 488:
+                desc = "거절";
+                break;
+            case 500:
+                desc = "거절";
+                break;
+            case 501:
+                desc = "거절";
+                break;
+            case 502:
+                desc = "거절";
+                break;
+            case 503:
+                desc = "거절";
+                break;
+            case 504:
+                desc = "거절";
+                break;
+            case 505:
+                desc = "거절";
+                break;
+            case 600:
+                desc = "거절";
+                break;
+            case 603:
+                desc = "거절";
+                break;
+            case 604:
+                desc = "거절";
+                break;
+            case 606:
+                desc = "거절";
+                break;
+            case 700:
+                desc = "통화종료";
+                break;
+        }
+        return desc;
+    }
+}

+ 21 - 0
WallPadCall/src/main/java/bssoft/stack/sip/Frequent.java

@@ -0,0 +1,21 @@
+package bssoft.stack.sip;
+
+public class Frequent {
+    public int _id;
+
+    public String phone;
+
+    public String name;
+
+    public Frequent() {
+        this._id = 0;
+        this.phone = "";
+        this.name = "";
+    }
+
+    public Frequent(int id, String phone, String name) {
+        this._id = id;
+        this.phone = phone;
+        this.name = name;
+    }
+}

+ 36 - 0
WallPadCall/src/main/java/bssoft/stack/sip/GetIpDns.java

@@ -0,0 +1,36 @@
+package bssoft.stack.sip;
+
+public class GetIpDns {
+    public String sipServerHost = "";
+
+    public String strId = "";
+
+    public String strCid = "";
+
+    public String strAuthid = "";
+
+    public String strAuthpassword = "";
+
+    public String strServerHost = "";
+
+    public String strServerDomain = "";
+
+    public int serverPort = 5060;
+
+    public boolean bSipAddressResolved = false;
+
+    public int sipTry = 0;
+
+    public GetIpDns() {
+        this.sipServerHost = "";
+        this.bSipAddressResolved = false;
+        this.sipTry = 0;
+        this.strId = "";
+        this.strCid = "";
+        this.strAuthid = "";
+        this.strAuthpassword = "";
+        this.strServerHost = "";
+        this.strServerDomain = "";
+        this.serverPort = 5060;
+    }
+}

+ 82 - 0
WallPadCall/src/main/java/bssoft/stack/sip/History.java

@@ -0,0 +1,82 @@
+package bssoft.stack.sip;
+
+public class History {
+    public int _id;
+
+    public String phone;
+
+    public String ani;
+
+    public String dnis;
+
+    public String name;
+
+    public String date;
+
+    public String direction;
+
+    public String code;
+
+    public String duration;
+
+    public String calltype;
+
+    public String callhandle;
+
+    public String check;
+
+    public String view;
+
+    public int count;
+
+    public History() {
+        this._id = 0;
+        this.phone = "";
+        this.ani = "";
+        this.dnis = "";
+        this.name = "";
+        this.date = "";
+        this.direction = "";
+        this.code = "";
+        this.duration = "";
+        this.calltype = "";
+        this.callhandle = "";
+        this.count = 0;
+        this.check = "0";
+        this.view = "0";
+    }
+
+    public History(int id, String phone, String ani, String dnis, String name, String date, String direction, String code, String duration, String calltype, String callhandle) {
+        this._id = id;
+        this.phone = phone;
+        this.ani = ani;
+        this.dnis = dnis;
+        this.name = name;
+        this.date = date;
+        this.direction = direction;
+        this.code = code;
+        this.duration = duration;
+        this.calltype = calltype;
+        this.callhandle = callhandle;
+        this.check = "0";
+        this.view = "0";
+        this.count = 1;
+    }
+
+    public History(int id, String phone, String ani, String dnis, String name, String date, String direction, String code, String duration, String calltype, String callhandle, String check, String view) {
+        this._id = id;
+        this.phone = phone;
+        this.ani = ani;
+        this.dnis = dnis;
+        this.name = name;
+        this.date = date;
+        this.direction = direction;
+        this.code = code;
+        this.duration = duration;
+        this.calltype = calltype;
+        this.callhandle = callhandle;
+        this.check = check;
+        this.view = view;
+        this.count = 1;
+    }
+}

+ 95 - 0
WallPadCall/src/main/java/bssoft/stack/sip/RFC2833.java

@@ -0,0 +1,95 @@
+package bssoft.stack.sip;
+
+public class RFC2833 {
+    public boolean bStart = false;
+
+    public boolean bEnd = false;
+
+    public static int payloadType = 101;
+
+    public int event = 0;
+
+    public int volume = 0;
+
+    public int reserved = 0;
+
+    public int edge = 0;
+
+    public int duration = 0;
+
+    public int exceedDuration = 0;
+
+    public boolean bActive;
+
+    public boolean flag;
+
+    public byte[] rfcdata = new byte[4];
+
+    public RFC2833() {
+        this.bActive = false;
+        this.flag = true;
+    }
+
+    public boolean setDtmf(int event, int volume, int reserved, int duration) {
+        System.out.println("DTMF SET :" + event + ":" + volume + ":" + reserved + ":" + duration);
+        this.bStart = true;
+        this.bEnd = false;
+        this.event = event;
+        this.volume = volume;
+        this.reserved = reserved;
+        this.edge = 0;
+        this.duration = duration;
+        this.bActive = true;
+        return true;
+    }
+
+    public boolean resetDtmf() {
+        this.bStart = false;
+        this.bEnd = false;
+        this.event = 0;
+        this.volume = 0;
+        this.reserved = 0;
+        this.edge = 0;
+        this.duration = 0;
+        this.exceedDuration = 0;
+        this.bActive = false;
+        return true;
+    }
+
+    public byte[] constructDtmfPacket() {
+        int field = 0;
+        field = this.event;
+        this.rfcdata[0] = (byte)(field << 24 >> 24);
+        field = 0;
+        field = this.volume << 26 >> 26 & 0x3F;
+        field |= this.edge << 31 >> 24 & 0x80;
+        this.rfcdata[1] = (byte)(field << 24 >> 24);
+        field = this.duration;
+        this.rfcdata[2] = (byte)(field << 16 >> 24);
+        this.rfcdata[3] = (byte)(field << 24 >> 24);
+        return this.rfcdata;
+    }
+
+    public byte[] constructDtmfPacket(int consumeduration) {
+        if (this.exceedDuration >= this.duration)
+            return null;
+        if (this.exceedDuration > 0)
+            this.bStart = false;
+        this.exceedDuration += consumeduration;
+        if (this.exceedDuration >= this.duration) {
+            this.edge = 1;
+            this.bEnd = true;
+        }
+        int field = 0;
+        field = this.event;
+        this.rfcdata[0] = (byte)(field << 24 >> 24);
+        field = 0;
+        field = this.volume << 26 >> 26 & 0x3F;
+        field |= this.edge << 31 >> 24 & 0x80;
+        this.rfcdata[1] = (byte)(field << 24 >> 24);
+        field = this.duration;
+        this.rfcdata[2] = (byte)(field << 16 >> 24);
+        this.rfcdata[3] = (byte)(field << 24 >> 24);
+        return this.rfcdata;
+    }
+}

+ 328 - 0
WallPadCall/src/main/java/bssoft/stack/sip/RTPCore.java

@@ -0,0 +1,328 @@
+package bssoft.stack.sip;
+
+import java.net.DatagramPacket;
+import java.util.Date;
+
+public class RTPCore {
+    public int RTP_PORT = 0;
+
+    public int mediaType = SIPStack.SIP_MEDIATYPE_NONE;
+
+    public byte[] buffer = null;
+
+    public byte[] pcmLinearBuffer = null;
+
+    public boolean bRTPlooping = false;
+
+    public boolean bRTPparsing = false;
+
+    public boolean bActive = false;
+
+    public int RTPversion = 0;
+
+    public int RTPpadding = 0;
+
+    public int RTPextension = 0;
+
+    public int RTPcsrc = 0;
+
+    public int RTPmark = 0;
+
+    public int RTPpayload = 0;
+
+    public int RTPsequence = 0;
+
+    public int RTPtimestamp = 0;
+
+    public int RTPssrc = 0;
+
+    public byte[] rtpPacketBuffer = null;
+
+    public byte[] rtpBulkBuffer = null;
+
+    public byte[] fieldBytes = null;
+
+    public byte[] rtpfieldBytes = null;
+
+    public boolean running = false;
+
+    public int remotePayloadType = SIPStack.SIP_CODEC_NONE;
+
+    public String remoteMediaIp = null;
+
+    public int remoteMediaPort = 0;
+
+    public boolean bDtmfDetected = false;
+
+    public int detectedDtmf = 0;
+
+    public Date rtpArrivalTime = null;
+
+    public int packetSize = 0;
+
+    public int PARSEversion = 0;
+
+    public int PARSEpadding = 0;
+
+    public int PARSEextension = 0;
+
+    public int PARSEcsrc = 0;
+
+    public int PARSEmark = 0;
+
+    public int PARSEpayload = 0;
+
+    public int PARSEsequence = 0;
+
+    public int PARSEtimestamp = 0;
+
+    public int PARSEssrc = 0;
+
+    public int PARSERFCdtmf = 0;
+
+    public int PARSERFCedge = 0;
+
+    public int PARSERFCvolume = 0;
+
+    public int PARSERFCduration = 0;
+
+    public RTPCore(int port, int mediaType) {
+        if (!SIPStack.bStackLicensed) {
+            System.out.println("라이슨스키를 설정하세요.");
+                    //System.exit(0);
+        }
+        this.RTP_PORT = port;
+        this.pcmLinearBuffer = new byte[1024];
+        this.rtpPacketBuffer = new byte[512];
+        this.rtpBulkBuffer = new byte[512];
+        this.fieldBytes = new byte[4];
+        this.rtpfieldBytes = new byte[4];
+        this.RTPversion = 2;
+        this.RTPpadding = 0;
+        this.RTPextension = 0;
+        this.RTPcsrc = 0;
+        this.RTPmark = 0;
+        this.RTPpayload = 0;
+        this.RTPsequence = 0;
+        Date date = new Date();
+        this.RTPtimestamp = (int)date.getTime();
+        this.RTPssrc = (int)date.getTime();
+        this.mediaType = mediaType;
+        if (mediaType == SIPStack.SIP_MEDIATYPE_AUDIO) {
+            this.buffer = new byte[SIPStack.RTP_AUDIO_SIZE];
+        } else if (mediaType == SIPStack.SIP_MEDIATYPE_VIDEO) {
+            this.buffer = new byte[65507];
+        } else {
+            this.buffer = new byte[65507];
+        }
+        this.bActive = false;
+        this.bDtmfDetected = false;
+        this.detectedDtmf = 0;
+        this.rtpArrivalTime = new Date();
+    }
+
+    public boolean encodeRtpHeader(byte[] header, int version, int padding, int extension, int csrc, int mark, int payload, int sequence, int timestamp, int ssrc) {
+        if (header == null || header.length < 12)
+            return false;
+        int iField = 0;
+        int iAppend = 0;
+        iField = version << 6 & 0xC0;
+        iAppend = padding << 5 & 0x20;
+        iField |= iAppend;
+        iAppend = extension << 4 & 0x10;
+        iField |= iAppend;
+        iAppend = csrc & 0xF;
+        iField |= iAppend;
+        header[0] = (byte)iField;
+        iField = 0;
+        iField = mark << 7 & 0x80;
+        iAppend = payload & 0x7F;
+        iField |= iAppend;
+        header[1] = (byte)iField;
+        iField = 0;
+        header[2] = (byte)(sequence << 16 >> 24);
+        header[3] = (byte)(sequence << 24 >> 24);
+        header[4] = (byte)(timestamp >> 24);
+        header[5] = (byte)(timestamp << 8 >> 24);
+        header[6] = (byte)(timestamp << 16 >> 24);
+        header[7] = (byte)(timestamp << 24 >> 24);
+        header[8] = (byte)(ssrc >> 24);
+        header[9] = (byte)(ssrc << 8 >> 24);
+        header[10] = (byte)(ssrc << 16 >> 24);
+        header[11] = (byte)(ssrc << 24 >> 24);
+        return true;
+    }
+
+    public boolean encodeRtpHeader(int payload) {
+        if (this.rtpPacketBuffer == null || this.rtpPacketBuffer.length < 12)
+            return false;
+        int iField = 0;
+        int iAppend = 0;
+        iField = this.RTPversion << 6 & 0xC0;
+        iAppend = this.RTPpadding << 5 & 0x20;
+        iField |= iAppend;
+        iAppend = this.RTPextension << 4 & 0x10;
+        iField |= iAppend;
+        iAppend = this.RTPcsrc & 0xF;
+        iField |= iAppend;
+        this.rtpPacketBuffer[0] = (byte)iField;
+        iField = 0;
+        iField = this.RTPmark << 7 & 0x80;
+        iAppend = payload & 0x7F;
+        iField |= iAppend;
+        this.rtpPacketBuffer[1] = (byte)iField;
+        iField = 0;
+        this.rtpPacketBuffer[2] = (byte)(this.RTPsequence << 16 >> 24);
+        this.rtpPacketBuffer[3] = (byte)(this.RTPsequence << 24 >> 24);
+        this.rtpPacketBuffer[4] = (byte)(this.RTPtimestamp >> 24);
+        this.rtpPacketBuffer[5] = (byte)(this.RTPtimestamp << 8 >> 24);
+        this.rtpPacketBuffer[6] = (byte)(this.RTPtimestamp << 16 >> 24);
+        this.rtpPacketBuffer[7] = (byte)(this.RTPtimestamp << 24 >> 24);
+        this.rtpPacketBuffer[8] = (byte)(this.RTPssrc >> 24);
+        this.rtpPacketBuffer[9] = (byte)(this.RTPssrc << 8 >> 24);
+        this.rtpPacketBuffer[10] = (byte)(this.RTPssrc << 16 >> 24);
+        this.rtpPacketBuffer[11] = (byte)(this.RTPssrc << 24 >> 24);
+        return true;
+    }
+
+    public int getBytesToInt(byte[] bytes) {
+        int newValue = 0;
+        newValue |= bytes[0] << 24 & 0xFF000000;
+        newValue |= bytes[1] << 16 & 0xFF0000;
+        newValue |= bytes[2] << 8 & 0xFF00;
+        newValue |= bytes[3] & 0xFF;
+        return newValue;
+    }
+
+    public byte[] getIntToBytes(int iValue) {
+        byte[] newbytes = new byte[4];
+        newbytes[0] = (byte)(iValue >> 24);
+        newbytes[1] = (byte)(iValue << 8 >> 24);
+        newbytes[2] = (byte)(iValue << 16 >> 24);
+        newbytes[3] = (byte)(iValue << 24 >> 24);
+        return newbytes;
+    }
+
+    public boolean setRTPPort(int port) {
+        if (port <= 0)
+            return false;
+        this.RTP_PORT = port;
+        return true;
+    }
+
+    public void setRemoteMediaInfo(int payloadtype, String mediaIp, int mediaPort) {
+        this.remotePayloadType = payloadtype;
+        this.remoteMediaIp = mediaIp;
+        this.remoteMediaPort = mediaPort;
+    }
+
+    public void parseRtpHeader(byte[] buffer) {
+        if (buffer == null || buffer.length < 12)
+            return;
+        this.fieldBytes[0] = buffer[0];
+        int version = this.fieldBytes[0] >> 6 & 0x3;
+        System.out.println("VERSION:" + version);
+        this.fieldBytes[0] = buffer[1];
+        int payloadType = this.fieldBytes[0] & Byte.MAX_VALUE;
+        System.out.println("Payload:" + payloadType);
+        this.fieldBytes[0] = 0;
+        this.fieldBytes[1] = 0;
+        this.fieldBytes[2] = buffer[2];
+        this.fieldBytes[3] = buffer[3];
+        int sequencNumber = getBytesToInt(this.fieldBytes);
+        System.out.println("SEQUENCE NUMBER:" + sequencNumber);
+        this.fieldBytes[0] = buffer[4];
+        this.fieldBytes[1] = buffer[5];
+        this.fieldBytes[2] = buffer[6];
+        this.fieldBytes[3] = buffer[7];
+        int timeStamp = getBytesToInt(this.fieldBytes);
+        System.out.println("TIMESTAMP:" + timeStamp);
+        this.fieldBytes[0] = buffer[8];
+        this.fieldBytes[1] = buffer[9];
+        this.fieldBytes[2] = buffer[10];
+        this.fieldBytes[3] = buffer[11];
+        int ssrc = getBytesToInt(this.fieldBytes);
+        System.out.println("SSRC:" + ssrc);
+    }
+
+    public void init() {
+        this.RTPversion = 2;
+        this.RTPpadding = 0;
+        this.RTPextension = 0;
+        this.RTPcsrc = 0;
+        this.RTPmark = 0;
+        this.RTPpayload = 0;
+        this.RTPsequence = 0;
+        Date date = new Date();
+        this.RTPtimestamp = (int)date.getTime();
+        this.RTPssrc = (int)date.getTime();
+        this.bDtmfDetected = false;
+        this.detectedDtmf = 0;
+        this.bActive = false;
+        this.rtpArrivalTime = new Date();
+    }
+
+    public boolean parseRTPHeader() {
+        try {
+            this.PARSEversion = 0;
+            this.PARSEpadding = 0;
+            this.PARSEextension = 0;
+            this.PARSEcsrc = 0;
+            this.PARSEmark = 0;
+            this.PARSEpayload = 0;
+            this.PARSEsequence = 0;
+            this.PARSEtimestamp = 0;
+            this.PARSEssrc = 0;
+            this.rtpfieldBytes[0] = this.buffer[1];
+            this.PARSEmark = this.rtpfieldBytes[0] >> 7 & 0x1;
+            this.PARSEpayload = this.rtpfieldBytes[0] & Byte.MAX_VALUE;
+        } catch (Exception e) {
+            return false;
+        }
+        return true;
+    }
+
+    public String getRemotAddress(DatagramPacket dp) {
+        String strIp = "0.0.0.0:0";
+        try {
+            byte[] address = dp.getAddress().getAddress();
+            if (address.length == 4) {
+                int unsignedByte1 = (address[0] < 0) ? (address[0] + 256) : address[0];
+                int unsignedByte2 = (address[1] < 0) ? (address[1] + 256) : address[1];
+                int unsignedByte3 = (address[2] < 0) ? (address[2] + 256) : address[2];
+                int unsignedByte4 = (address[3] < 0) ? (address[3] + 256) : address[3];
+                strIp = String.valueOf(unsignedByte1) + "." + unsignedByte2 + "." + unsignedByte3 + "." + unsignedByte4 + ":" + dp.getPort();
+            }
+        } catch (Exception exception) {}
+        return strIp;
+    }
+
+    public boolean parseRFC2833() {
+        this.PARSERFCdtmf = 0;
+        this.PARSERFCedge = 0;
+        this.PARSERFCvolume = 0;
+        this.PARSERFCduration = 0;
+        try {
+            int field = 0;
+            this.PARSERFCdtmf = this.buffer[12];
+            field = this.buffer[13];
+            this.PARSERFCedge = (field & 0x80) >> 7;
+            this.PARSERFCvolume = field & 0x3F;
+            this.PARSERFCduration = this.buffer[14] << 24 >> 16 & 0xFF00;
+            this.PARSERFCduration |= this.buffer[15] << 24 >> 24 & 0xFF;
+            return true;
+        } catch (Exception exception) {
+            return false;
+        }
+    }
+
+    public String getVideomediadescription() {
+        int port = this.RTP_PORT + 2;
+        String str = "m=video " + port + " RTP/AVP " + SIPStack.SIP_CODEC_H264 + SIPStack.SIP_LINE_END +
+                "a=rtpmap:" + SIPStack.SIP_CODEC_H264 + " H264/90000" + SIPStack.SIP_LINE_END +
+                "a=fmtp:" + SIPStack.SIP_CODEC_H264 + " packetization-mode=1;profile-level-id=2" + SIPStack.SIP_LINE_END +
+                "a=cliprect:0,0,240,320" + SIPStack.SIP_LINE_END +
+                "a=framesize:" + SIPStack.SIP_CODEC_H264 + " 320-240" + SIPStack.SIP_LINE_END;
+        return str;
+    }
+}

+ 316 - 0
WallPadCall/src/main/java/bssoft/stack/sip/SDPMedia.java

@@ -0,0 +1,316 @@
+package bssoft.stack.sip;
+
+import java.util.StringTokenizer;
+
+public class SDPMedia {
+    public int mediaType = SIPStack.SIP_MEDIATYPE_NONE;
+
+    public String mediaIp = null;
+
+    public int mediaPort = 0;
+
+    public int flowIndicator = SIPStack.SIP_MEDIAFLOW_NONE;
+
+    public StringBuffer rtpmapBuffer = null;
+
+    public StringBuffer fmtpBuffer = null;
+
+    public String flow = "sendrecv";
+
+    public StringBuffer codecS = null;
+
+    public int commonCodec = -1;
+
+    public boolean flag = false;
+
+    public String mediaString = null;
+
+    public SDPMedia(int mediatype) {
+        if (!SIPStack.bStackLicensed) {
+            System.out.println("라이슨스키를 설정하세요.");
+                    //System.exit(0);
+        }
+        this.mediaType = mediatype;
+        this.mediaIp = null;
+        this.mediaPort = 0;
+        this.rtpmapBuffer = new StringBuffer();
+        this.fmtpBuffer = new StringBuffer();
+        this.flow = "sendrecv";
+        this.codecS = new StringBuffer();
+        this.commonCodec = -1;
+        this.flowIndicator = SIPStack.SIP_MEDIAFLOW_SENDRECV;
+        this.flag = true;
+    }
+
+    public SDPMedia(String mediadescribe, String platformIp) {
+        this.mediaType = SIPStack.SIP_MEDIATYPE_NONE;
+        this.mediaIp = platformIp;
+        this.mediaPort = 0;
+        this.rtpmapBuffer = new StringBuffer();
+        this.fmtpBuffer = new StringBuffer();
+        this.flow = "sendrecv";
+        this.codecS = new StringBuffer();
+        this.commonCodec = -1;
+        this.flowIndicator = SIPStack.SIP_MEDIAFLOW_SENDRECV;
+        boolean bContinueParse = true;
+        if (mediadescribe != null && mediadescribe.length() > 0) {
+            int iS = 0;
+            int iE = 0;
+            String header = null;
+            if (mediadescribe.startsWith("m=audio ")) {
+                this.mediaType = SIPStack.SIP_MEDIATYPE_AUDIO;
+            } else if (mediadescribe.startsWith("m=video ")) {
+                this.mediaType = SIPStack.SIP_MEDIATYPE_VIDEO;
+            } else {
+                bContinueParse = false;
+            }
+            if (bContinueParse) {
+                iE = mediadescribe.indexOf(SIPStack.SIP_LINE_END);
+                if (iE > 0) {
+                    header = mediadescribe.substring(0, iE);
+                    StringTokenizer st = new StringTokenizer(header, " ", true);
+                    int fieldCount = 0;
+                    while (st.hasMoreTokens()) {
+                        String str = st.nextToken().trim();
+                        if (str.length() > 0 && str.compareTo(" ") != 0) {
+                            if (fieldCount == 0) {
+                                if (str.compareTo("m=audio") != 0) {
+                                    bContinueParse = false;
+                                    break;
+                                }
+                            } else if (fieldCount == 1) {
+                                this.mediaPort = Integer.parseInt(str);
+                            } else if (fieldCount == 2) {
+                                if (str.compareTo("RTP/AVP") != 0) {
+                                    bContinueParse = false;
+                                    break;
+                                }
+                            } else if (fieldCount > 2) {
+                                if (this.codecS.length() > 0) {
+                                    this.codecS.append(" " + str);
+                                } else {
+                                    this.codecS.append(str);
+                                }
+                            }
+                            fieldCount++;
+                        }
+                    }
+                } else {
+                    bContinueParse = false;
+                }
+            }
+            if (bContinueParse) {
+                StringTokenizer st = new StringTokenizer(mediadescribe, "\n", true);
+                while (st.hasMoreTokens()) {
+                    String str = st.nextToken().trim();
+                    if (str.length() > 0 && str.startsWith("a=")) {
+                        if (str.startsWith("a=rtpmap:")) {
+                            this.rtpmapBuffer.append(String.valueOf(str) + "\n");
+                            continue;
+                        }
+                        if (str.startsWith("a=fmtp:")) {
+                            this.fmtpBuffer.append(String.valueOf(str) + "\n");
+                            continue;
+                        }
+                        if (str.startsWith("a=sendrecv")) {
+                            this.flow = "sendrecv";
+                            this.flowIndicator = SIPStack.SIP_MEDIAFLOW_SENDRECV;
+                            continue;
+                        }
+                        if (str.startsWith("a=sendonly")) {
+                            this.flow = "sendonly";
+                            this.flowIndicator = SIPStack.SIP_MEDIAFLOW_SENDONLY;
+                            continue;
+                        }
+                        if (str.startsWith("a=recvonly")) {
+                            this.flow = "recvonly";
+                            this.flowIndicator = SIPStack.SIP_MEDIAFLOW_RECVONLY;
+                        }
+                    }
+                }
+            }
+            if (bContinueParse && mediadescribe.indexOf("\nc=IN IP4 ") > 0) {
+                iS = 0;
+                iE = 0;
+                iS = mediadescribe.indexOf("c=");
+                if (iS >= 0) {
+                    iE = mediadescribe.indexOf(SIPStack.SIP_LINE_END, iS);
+                    header = "";
+                    if (iS >= 0 && iE > iS) {
+                        header = mediadescribe.substring(iS, iE + 2);
+                        iE = header.indexOf(SIPStack.SIP_LINE_END);
+                        this.mediaIp = header.substring("c=IN IP4 ".length(), iE);
+                    }
+                }
+            }
+        }
+        if (!bContinueParse)
+            resetMedia();
+        this.flag = true;
+    }
+
+    public void resetMedia() {
+        this.mediaType = SIPStack.SIP_MEDIATYPE_NONE;
+        this.mediaIp = null;
+        this.mediaPort = 0;
+        this.rtpmapBuffer = null;
+        this.fmtpBuffer = null;
+        this.flow = "sendrecv";
+        this.flowIndicator = SIPStack.SIP_MEDIAFLOW_SENDRECV;
+        this.codecS = null;
+        this.commonCodec = -1;
+        this.flag = false;
+        this.mediaString = null;
+    }
+
+    public String getMediaString() {
+        if (!this.flag)
+            return null;
+        String mString = "";
+        String aString = "";
+        String fmtpString = "";
+        String flowString = "a=" + this.flow + SIPStack.SIP_LINE_END;
+        if (this.mediaType == SIPStack.SIP_MEDIATYPE_AUDIO) {
+            mString = "m=audio " + this.mediaPort + " RTP/AVP " + this.codecS.toString() + SIPStack.SIP_LINE_END;
+        } else if (this.mediaType != SIPStack.SIP_MEDIATYPE_VIDEO) {
+            return null;
+        }
+        if (this.rtpmapBuffer.length() > 0)
+            aString = this.rtpmapBuffer.toString();
+        if (this.fmtpBuffer.length() > 0)
+            fmtpString = this.fmtpBuffer.toString();
+        this.mediaString = String.valueOf(mString) +
+                aString +
+                fmtpString +
+                flowString;
+        return this.mediaString;
+    }
+
+    public String getFinalMediaString() {
+        if (!this.flag)
+            return null;
+        if (this.commonCodec < 0)
+            return null;
+        String mString = "";
+        String aString = "";
+        String flowString = "a=" + this.flow + SIPStack.SIP_LINE_END;
+        if (this.mediaType == SIPStack.SIP_MEDIATYPE_AUDIO) {
+            mString = "m=audio " + this.mediaPort + " RTP/AVP " + this.commonCodec + SIPStack.SIP_LINE_END;
+        } else if (this.mediaType != SIPStack.SIP_MEDIATYPE_VIDEO) {
+            return null;
+        }
+        if (this.commonCodec == 0) {
+            aString = "a=rtpmap:0 PCMU/8000" + SIPStack.SIP_LINE_END;
+        } else if (this.commonCodec == 8) {
+            aString = "a=rtpmap:8 PCMA/8000" + SIPStack.SIP_LINE_END;
+        } else if (this.commonCodec == 18) {
+            aString = "a=rtpmap:18 G729/8000" + SIPStack.SIP_LINE_END;
+        }
+        this.mediaString = String.valueOf(mString) +
+                aString +
+                flowString;
+        return this.mediaString;
+    }
+
+    public boolean setMediaAddress(String ip, int port) {
+        if (!this.flag)
+            return false;
+        if (port < 0 || port > 65556)
+            return false;
+        this.mediaIp = ip;
+        this.mediaPort = port;
+        return true;
+    }
+
+    public boolean setCodec(int codec) {
+        if (!this.flag)
+            return false;
+        if (this.codecS.length() > 0) {
+            this.codecS.append(" " + codec);
+        } else {
+            this.codecS.append(codec);
+        }
+        return true;
+    }
+
+    public boolean setCodec(int codec, String describe) {
+        if (!this.flag)
+            return false;
+        setCodec(codec);
+        this.rtpmapBuffer.append("a=rtpmap:" + codec + " " + describe + SIPStack.SIP_LINE_END);
+        return true;
+    }
+
+    public boolean setFmtpDescribe(int codec, String describe) {
+        if (!this.flag)
+            return false;
+        this.fmtpBuffer.append("a=fmtp:" + codec + " " + describe + SIPStack.SIP_LINE_END);
+        return true;
+    }
+
+    public boolean setCommonCodec(int codec) {
+        if (!this.flag)
+            return false;
+        this.commonCodec = codec;
+        return true;
+    }
+
+    public boolean setFlow(String flow) {
+        if (flow == null)
+            return false;
+        if (!this.flag)
+            return false;
+        this.flow = flow;
+        if (flow.compareTo("sendrecv") == 0) {
+            this.flowIndicator = SIPStack.SIP_MEDIAFLOW_SENDRECV;
+        } else if (flow.compareTo("sendonly") == 0) {
+            this.flowIndicator = SIPStack.SIP_MEDIAFLOW_SENDONLY;
+        } else if (flow.compareTo("recvonly") == 0) {
+            this.flowIndicator = SIPStack.SIP_MEDIAFLOW_RECVONLY;
+        } else {
+            this.flowIndicator = SIPStack.SIP_MEDIAFLOW_NONE;
+        }
+        return true;
+    }
+
+    public int negotiateAudioCodec(String sideCodecs) {
+        if (this.codecS == null || this.codecS.length() <= 0)
+            return -1;
+        String myCodecs = this.codecS.toString();
+        myCodecs.trim();
+        if (myCodecs == null || myCodecs.length() <= 0)
+            return -1;
+        sideCodecs.trim();
+        if (sideCodecs == null || sideCodecs.length() <= 0)
+            return -1;
+        StringTokenizer my_st = new StringTokenizer(myCodecs, " ", true);
+        String str = null;
+        int codec = -1;
+        while (my_st.hasMoreTokens()) {
+            str = my_st.nextToken().trim();
+            if (str == null || str.length() == 0)
+                continue;
+            codec = Integer.parseInt(str);
+            if (codec >= 0 && codec < 100) {
+                StringTokenizer side_st = new StringTokenizer(sideCodecs, " ", true);
+                int sidecodec = -1;
+                boolean bDecided = false;
+                while (side_st.hasMoreTokens()) {
+                    str = side_st.nextToken().trim();
+                    if (str == null || str.length() == 0)
+                        continue;
+                    sidecodec = Integer.parseInt(str);
+                    if (str.length() > 0 && sidecodec >= 0 && codec < 100)
+                        if (sidecodec == codec) {
+                            bDecided = true;
+                            this.commonCodec = codec;
+                            break;
+                        }
+                }
+                if (bDecided)
+                    return this.commonCodec;
+            }
+        }
+        return -1;
+    }
+}

+ 138 - 0
WallPadCall/src/main/java/bssoft/stack/sip/SIPAUTHENTICATEHeader.java

@@ -0,0 +1,138 @@
+package bssoft.stack.sip;
+
+public class SIPAUTHENTICATEHeader {
+    public String header = null;
+
+    public String headerValue = null;
+
+    public String realmValue = null;
+
+    public String nonceValue = null;
+
+    public String qopValue = null;
+
+    public String strStale = null;
+
+    public String strAlgorithm = null;
+
+    public int headerType = SIPStack.SIP_HEADERTYPE_NONE;
+
+    public boolean flag = false;
+
+    public SIPAUTHENTICATEHeader(String header, int headerType) {
+        if (header != null) {
+            String keyWord;
+            if (headerType == SIPStack.SIP_HEADERTYPE_WWWAUTHENTICATE) {
+                keyWord = "WWW-Authenticate: ";
+            } else if (headerType == SIPStack.SIP_HEADERTYPE_WwwAUTHENTICATE) {
+                keyWord = "Www-Authenticate: ";
+            } else if (headerType == SIPStack.SIP_HEADERTYPE_PROXYAUTHENTICATE) {
+                keyWord = "Proxy-Authenticate: ";
+            } else {
+                keyWord = null;
+            }
+            if (keyWord != null)
+                if (header.startsWith(keyWord)) {
+                    this.headerType = headerType;
+                    this.header = header;
+                    this.flag = true;
+                    int iS = 0;
+                    int iE = 0;
+                    String strRealm = null;
+                    iS = header.indexOf("realm=");
+                    iE = 0;
+                    if (iS >= 0) {
+                        iE = header.indexOf(",", iS);
+                        if (iE > 0) {
+                            strRealm = header.substring(iS, iE);
+                        } else if (iE < 0) {
+                            strRealm = header.substring(iS);
+                        }
+                        if (strRealm.length() > 0) {
+                            iS = strRealm.indexOf("=");
+                            String strValue = strRealm.substring(iS + 1);
+                            strValue = strValue.trim();
+                            if (strValue.indexOf("\"") == 0)
+                                iS = 1;
+                            if (iS > 0)
+                                iE = strValue.indexOf("\"", iS);
+                            this.realmValue = strValue.substring(iS, iE);
+                        }
+                    } else {
+                        this.realmValue = "";
+                    }
+                    String strQop = null;
+                    iS = header.indexOf("qop=");
+                    iE = 0;
+                    if (iS >= 0) {
+                        iE = header.indexOf(",", iS);
+                        if (iE > 0) {
+                            strQop = header.substring(iS, iE);
+                        } else if (iE < 0) {
+                            strQop = header.substring(iS);
+                        }
+                        this.qopValue = "";
+                        if (strQop.length() > 0) {
+                            iS = strQop.indexOf("=");
+                            String strValue = strQop.substring(iS + 1);
+                            strValue = strValue.trim();
+                            if (strValue.indexOf("\"") == 0)
+                                iS = 1;
+                            if (iS > 0)
+                                iE = strValue.indexOf("\"", iS);
+                            this.qopValue = strValue.substring(iS, iE);
+                        }
+                    } else {
+                        this.qopValue = "";
+                    }
+                    String strNonce = null;
+                    iS = header.indexOf("nonce=");
+                    iE = 0;
+                    if (iS >= 0) {
+                        iE = header.indexOf(",", iS);
+                        if (iE > 0) {
+                            strNonce = header.substring(iS, iE);
+                        } else if (iE < 0) {
+                            strNonce = header.substring(iS);
+                        }
+                        if (strNonce.length() > 0) {
+                            iS = strNonce.indexOf("=");
+                            String strValue = strNonce.substring(iS + 1);
+                            strValue = strValue.trim();
+                            if (strValue.indexOf("\"") == 0)
+                                iS = 1;
+                            if (iS > 0)
+                                iE = strValue.indexOf("\"", iS);
+                            this.nonceValue = strValue.substring(iS, iE);
+                        }
+                    } else {
+                        this.nonceValue = "";
+                    }
+                    iS = header.indexOf("stale=");
+                    iE = 0;
+                    if (iS >= 0) {
+                        iE = header.indexOf(",", iS);
+                        if (iE > 0) {
+                            this.strStale = header.substring(iS + 6, iE);
+                        } else if (iE < 0) {
+                            this.strStale = header.substring(iS + 6);
+                        }
+                    } else {
+                        this.strStale = "";
+                    }
+                    iS = header.indexOf("algorithm=");
+                    iE = 0;
+                    if (iS >= 0) {
+                        iE = header.indexOf(",", iS);
+                        if (iE > 0) {
+                            this.strAlgorithm = header.substring(iS + 10, iE);
+                        } else if (iE < 0) {
+                            this.strAlgorithm = header.substring(iS + 10);
+                        }
+                    } else {
+                        this.strAlgorithm = "";
+                    }
+                }
+        }
+    }
+}

+ 330 - 0
WallPadCall/src/main/java/bssoft/stack/sip/SIPCONTACTHeader.java

@@ -0,0 +1,330 @@
+package bssoft.stack.sip;
+
+public class SIPCONTACTHeader {
+    public String header = null;
+
+    public String headerValue = null;
+
+    public int expires = -1;
+
+    public String display = null;
+
+    public String username = null;
+
+    public String sipuri = null;
+
+    public String uriusertag = null;
+
+    public String ip = null;
+
+    public int port = 0;
+
+    public String tag = null;
+
+    public boolean flag = false;
+
+    public SIPCONTACTHeader(String message) {
+        if (message != null && message.length() > 0) {
+            int iS = message.indexOf("Contact: ");
+            int iE = 0;
+            if (iS < 0) {
+                iS = message.indexOf(String.valueOf(SIPStack.SIP_LINE_END) + "m: ");
+                if (iS >= 0)
+                    iS += 2;
+            }
+            if (iS >= 0) {
+                iE = message.indexOf(SIPStack.SIP_LINE_END, iS);
+                if (iE > 0) {
+                    this.header = message.substring(iS, iE);
+                    if (this.header.startsWith("Contact: ")) {
+                        this.headerValue = this.header.substring(9);
+                    } else if (this.header.startsWith("m: ")) {
+                        this.headerValue = this.header.substring(3);
+                    }
+                    String strExpires = null;
+                    iS = this.headerValue.indexOf(";expires=");
+                    iE = 0;
+                    if (iS >= 0) {
+                        iE = this.headerValue.indexOf(";", iS + 1);
+                        int iE_ = this.headerValue.indexOf(",", iS + 1);
+                        if (iE_ > 0 && iE_ < iE)
+                            iE = iE_;
+                        if (iE > 0) {
+                            strExpires = this.headerValue.substring(iS, iE);
+                        } else if (iE < 0) {
+                            strExpires = this.headerValue.substring(iS);
+                        }
+                        if (strExpires != null && strExpires.length() > 0)
+                            this.expires = Integer.parseInt(strExpires.substring(9).trim());
+                    }
+                }
+            }
+            iS = 0;
+            iE = 0;
+            if (this.headerValue != null && this.headerValue.length() > 0) {
+                iE = this.headerValue.indexOf("<sip:");
+                if (iE > 0) {
+                    String str = null;
+                    str = this.headerValue.substring(0, iE).trim();
+                    if (str != null && str.length() > 1 &&
+                            str.startsWith("\"") &&
+                            str.endsWith("\"")) {
+                        this.display = str.substring(1, str.length() - 1);
+                    } else if (str != null && str.length() > 0) {
+                        this.display = str;
+                    }
+                }
+                iS = this.headerValue.indexOf("sip:");
+                if (iS > 0) {
+                    String str = null;
+                    iE = this.headerValue.indexOf(">", iS + 4);
+                    if (iE < 0)
+                        iE = this.headerValue.indexOf(";", iS + 4);
+                    if (iE > 0) {
+                        str = this.headerValue.substring(iS, iE);
+                    } else {
+                        str = this.headerValue.substring(iS);
+                    }
+                    if (str != null && str.length() > 0)
+                        this.sipuri = str.trim();
+                }
+                if (this.sipuri != null && this.sipuri.length() > 0) {
+                    iS = this.sipuri.indexOf("@", 4);
+                    if (iS > 0)
+                        this.username = this.sipuri.substring(4, iS).trim();
+                }
+                if (this.sipuri != null && this.sipuri.length() > 0) {
+                    iS = this.sipuri.indexOf("@", 4);
+                    iE = this.sipuri.indexOf(";", 4);
+                    String str = null;
+                    if (iS >= 0 && iE >= 0) {
+                        str = this.sipuri.substring(iS + 1, iE).trim();
+                    } else if (iS >= 0) {
+                        str = this.sipuri.substring(iS + 1).trim();
+                    } else if (iE >= 0) {
+                        str = this.sipuri.substring(4, iE).trim();
+                    } else {
+                        str = this.sipuri.substring(4).trim();
+                    }
+                    this.port = 5060;
+                    if (str != null && str.length() > 0) {
+                        iS = str.indexOf(":");
+                        if (iS > 0) {
+                            this.port = Integer.parseInt(str.substring(iS + 1).trim());
+                            this.ip = str.substring(0, iS);
+                        } else {
+                            this.ip = str;
+                        }
+                    }
+                }
+                iS = this.headerValue.indexOf(";tag=");
+                if (iS > 0) {
+                    String str = null;
+                    iE = this.headerValue.indexOf(";", iS + 5);
+                    if (iE >= 0) {
+                        if (iE > iS + 5) {
+                            str = this.headerValue.substring(iS + 5, iE);
+                        } else {
+                            str = "";
+                        }
+                    } else {
+                        str = this.headerValue.substring(iS + 5);
+                    }
+                    if (str != null && str.length() > 0)
+                        this.tag = str.trim();
+                }
+                iS = this.headerValue.indexOf("sip:");
+                if (iS > 0) {
+                    String str = null;
+                    iE = this.headerValue.indexOf(">", iS + 4);
+                    if (iE > 0)
+                        str = this.headerValue.substring(iS, iE);
+                    if (str != null && str.length() > 0) {
+                        iS = str.indexOf(";user=", iS + 4);
+                        if (iS > 0) {
+                            this.uriusertag = str.substring(iS + 6);
+                            if (this.uriusertag != null && this.uriusertag.length() > 0 && this.uriusertag.indexOf(";") >= 0)
+                                if (this.uriusertag.indexOf(";") == 0) {
+                                    this.uriusertag = null;
+                                } else {
+                                    this.uriusertag = this.uriusertag.substring(0, this.uriusertag.indexOf(";")).trim();
+                                }
+                        }
+                    }
+                }
+                this.flag = true;
+            }
+        }
+    }
+
+    public SIPCONTACTHeader(String message, String requesturi) {
+        if (message != null && message.length() > 0) {
+            int iS = message.indexOf("Contact: ");
+            int iE = 0;
+            if (iS < 0) {
+                iS = message.indexOf(String.valueOf(SIPStack.SIP_LINE_END) + "m: ");
+                if (iS >= 0)
+                    iS += 2;
+            }
+            if (iS >= 0) {
+                iE = message.indexOf(SIPStack.SIP_LINE_END, iS);
+                if (iE > 0) {
+                    this.header = message.substring(iS, iE);
+                    if (this.header.startsWith("Contact: ")) {
+                        this.headerValue = this.header.substring(9);
+                    } else if (this.header.startsWith("m: ")) {
+                        this.headerValue = this.header.substring(3);
+                    }
+                }
+            }
+            iS = 0;
+            iE = 0;
+            if (this.headerValue != null && this.headerValue.length() > 0) {
+                this.display = "";
+                String tempValue = this.headerValue;
+                iS = tempValue.indexOf("sip:");
+                String str = "";
+                boolean bFound = false;
+                while (iS >= 0) {
+                    tempValue = tempValue.substring(iS);
+                    iE = tempValue.indexOf(">", 4);
+                    if (iE < 0)
+                        iE = tempValue.indexOf(";", 4);
+                    if (iE > 0) {
+                        str = tempValue.substring(0, iE);
+                    } else {
+                        str = tempValue;
+                    }
+                    if (str != null && str.length() > 0)
+                        this.sipuri = str.trim();
+                    if (str != null &&
+                            str.length() > 0 &&
+                            requesturi != null &&
+                            requesturi.length() > 0 &&
+                            str.trim().compareTo(requesturi) == 0) {
+                        bFound = true;
+                        this.sipuri = str.trim();
+                        String strExpires = null;
+                        iS = tempValue.indexOf(";expires=");
+                        iE = 0;
+                        if (iS >= 0) {
+                            iE = tempValue.indexOf(";", iS + 1);
+                            int iE_ = tempValue.indexOf(",", iS + 1);
+                            if (iE_ > 0 && iE_ < iE)
+                                iE = iE_;
+                            if (iE > 0) {
+                                strExpires = tempValue.substring(iS, iE);
+                            } else if (iE < 0) {
+                                strExpires = tempValue.substring(iS);
+                            }
+                            if (strExpires != null && strExpires.length() > 0)
+                                this.expires = Integer.parseInt(strExpires.substring(9).trim());
+                        }
+                        break;
+                    }
+                    tempValue = tempValue.substring(iE + 1).trim();
+                    iS = tempValue.indexOf("sip:");
+                }
+                if (bFound) {
+                    if (this.sipuri != null && this.sipuri.length() > 0) {
+                        iS = this.sipuri.indexOf("@", 4);
+                        if (iS > 0)
+                            this.username = this.sipuri.substring(4, iS).trim();
+                    }
+                    if (this.sipuri != null && this.sipuri.length() > 0) {
+                        iS = this.sipuri.indexOf("@", 4);
+                        iE = this.sipuri.indexOf(";", 4);
+                        if (iS >= 0 && iE >= 0) {
+                            str = this.sipuri.substring(iS + 1, iE).trim();
+                        } else if (iS >= 0) {
+                            str = this.sipuri.substring(iS + 1).trim();
+                        } else if (iE >= 0) {
+                            str = this.sipuri.substring(4, iE).trim();
+                        } else {
+                            str = this.sipuri.substring(4).trim();
+                        }
+                        this.port = 5060;
+                        if (str != null && str.length() > 0) {
+                            iS = str.indexOf(":");
+                            if (iS > 0) {
+                                this.port = Integer.parseInt(str.substring(iS + 1).trim());
+                                this.ip = str.substring(0, iS);
+                            } else {
+                                this.ip = str;
+                            }
+                        }
+                    }
+                    iS = this.headerValue.indexOf(";tag=");
+                    if (iS > 0) {
+                        iE = this.headerValue.indexOf(";", iS + 5);
+                        if (iE >= 0) {
+                            if (iE > iS + 5) {
+                                str = this.headerValue.substring(iS + 5, iE);
+                            } else {
+                                str = "";
+                            }
+                        } else {
+                            str = this.headerValue.substring(iS + 5);
+                        }
+                        if (str != null && str.length() > 0) {
+                            this.tag = str.trim();
+                        } else {
+                            this.tag = "";
+                        }
+                    }
+                    iS = this.headerValue.indexOf("sip:");
+                    if (iS > 0) {
+                        iE = this.headerValue.indexOf(">", iS + 4);
+                        if (iE > 0)
+                            str = this.headerValue.substring(iS, iE);
+                        if (str != null && str.length() > 0) {
+                            iS = str.indexOf(";user=", iS + 4);
+                            if (iS > 0) {
+                                this.uriusertag = str.substring(iS + 6);
+                                if (this.uriusertag != null && this.uriusertag.length() > 0 && this.uriusertag.indexOf(";") >= 0)
+                                    if (this.uriusertag.indexOf(";") == 0) {
+                                        this.uriusertag = null;
+                                    } else {
+                                        this.uriusertag = this.uriusertag.substring(0, this.uriusertag.indexOf(";")).trim();
+                                    }
+                            }
+                        }
+                    }
+                    this.flag = true;
+                }
+            }
+        }
+    }
+
+    public String getDisplay() {
+        return this.display;
+    }
+
+    public String getUsername() {
+        return this.username;
+    }
+
+    public String getSipuri() {
+        return this.sipuri;
+    }
+
+    public String getSipuriusertag() {
+        return this.uriusertag;
+    }
+
+    public String getIp() {
+        return this.ip;
+    }
+
+    public int getPort() {
+        return this.port;
+    }
+
+    public String getTag() {
+        return this.tag;
+    }
+
+    public int getExpires() {
+        return this.expires;
+    }
+}

+ 2511 - 0
WallPadCall/src/main/java/bssoft/stack/sip/SIPCall.java

@@ -0,0 +1,2511 @@
+package bssoft.stack.sip;
+
+import java.util.Date;
+import java.util.StringTokenizer;
+
+public class SIPCall {
+    public String commandLine = null;
+
+    public String viaH = null;
+
+    public StringBuffer viaArray = new StringBuffer();
+
+    public String routeH = null;
+
+    public StringBuffer routeArray = new StringBuffer();
+
+    public String recordrouteH = null;
+
+    public StringBuffer recordrouteArray = new StringBuffer();
+
+    public String maxforwardH = null;
+
+    public String contactH = null;
+
+    public String toH = null;
+
+    public String fromH = null;
+
+    public String callidH = null;
+
+    public String cseqH = null;
+
+    public String expiresH = null;
+
+    public String allowH = null;
+
+    public String useragentH = null;
+
+    public String remoteuseragentH = null;
+
+    public String contentlengthH = null;
+
+    public String contenttypeH = null;
+
+    public String authorizationINVITEH = null;
+
+    public String authorizationCANCELH = null;
+
+    public String authorizationBYEH = null;
+
+    public String authorizationACKH = null;
+
+    public String passertedidentityH = null;
+
+    public String serverIp = null;
+
+    public int serverPort = 5060;
+
+    public String serverDomain = null;
+
+    public String remoteIp = null;
+
+    public int remotePort = 5060;
+
+    public String remoteContactIp = null;
+
+    public int remoteContactPort = 5060;
+
+    public String routeIp = null;
+
+    public int routePort = 5060;
+
+    public String remoteContactUri = null;
+
+    public String localIp = null;
+
+    public int localPort = 5060;
+
+    public String id = null;
+
+    public String cid = null;
+
+    public String authid = null;
+
+    public String authpassword = null;
+
+    public String fromTag = null;
+
+    public String toTag = null;
+
+    public String fromHeaderValue = null;
+
+    public String toHeaderValue = null;
+
+    public String callId = null;
+
+    public String dnis = null;
+
+    public String viaBranch = null;
+
+    public int CSEQ_NUMBER = SIPStack.SIP_SEQUENCE_INVITE;
+
+    public int INVITE_CSEQ = 0;
+
+    public int CANCEL_CSEQ = 0;
+
+    public int ACK_CSEQ = 0;
+
+    public int BYE_CSEQ = 0;
+
+    public int callDirection = SIPStack.SIP_CALLDIRECTION_NONE;
+
+    public int responseCode = 0;
+
+    public int callState = 0;
+
+    public int callMode = SIPStack.SIP_CALLMODE_NONE;
+
+    public Date callTime_TI = null;
+
+    public Date callTime_T0 = null;
+
+    public Date callTime_T00 = null;
+
+    public int invitingTimes = 0;
+
+    public Date callTime_T1 = null;
+
+    public Date callTime_T2 = null;
+
+    public Date callTime_T3 = null;
+
+    public Date callTime_T4 = null;
+
+    public Date callTime_T40 = null;
+
+    public Date callTime_T5 = null;
+
+    public Date callTime_T6 = null;
+
+    public Date callTime_T7 = null;
+
+    public Date callTime_T8 = null;
+
+    public Date callTime_T9 = null;
+
+    public int expiresTI = 0;
+
+    public int expiresT0 = 0;
+
+    public int expiresT00 = 0;
+
+    public int expiresT1 = 0;
+
+    public int expiresT2 = 0;
+
+    public int expiresT3 = 0;
+
+    public int expiresT4 = 0;
+
+    public int expiresT5 = 0;
+
+    public int expiresT6 = 0;
+
+    public int expiresT7 = 0;
+
+    public int expiresT8 = 0;
+
+    public int expiresT9 = 0;
+
+    public SIPSdp sdp = null;
+
+    public SIPSdp remoteSdp = null;
+
+    public String message = null;
+
+    public boolean flag;
+
+    public UPDATEHeaders updateHeaders = null;
+
+    public boolean bHolding = false;
+
+    public boolean bPending = false;
+
+    public boolean bDtmfdetected = false;
+
+    public int detectedDtmf = 0;
+
+    public int dtmfDuration = 0;
+
+    public boolean bCancelRequest = false;
+
+    public boolean bRejectRequest = false;
+
+    public boolean bNewcallRequest = false;
+
+    public boolean bUpdateRequest = false;
+
+    public boolean bAsMaster = false;
+
+    public boolean bForwardRequest = false;
+
+    public boolean bByedisconnected = false;
+
+    public String number = "";
+
+    public String dong_number = "";
+
+    public String ho_number = "";
+
+    public boolean bDirectcall = false;
+
+    public boolean bResponsebackgroundcall = false;
+
+    public boolean bResponsebackgroundcallReady = false;
+
+    public Date responsebackgroundcallTimer = new Date();
+
+    public int hnsOriginatorServiceType = BSSVideo.HNS_SERVICE_NONE;
+
+    public int hnsReceiverServiceType = BSSVideo.HNS_SERVICE_NONE;
+
+    public SIPCall() {
+        if (!SIPStack.bStackLicensed) {
+            System.out.println("라이슨스키를 설정하세요.");
+                    //System.exit(0);
+        }
+        if (SIPStack.SIP_CALLHANDLE_DEBUG)
+            System.out.println("call handle created.");
+        this.updateHeaders = new UPDATEHeaders();
+        this.CSEQ_NUMBER = SIPStack.SIP_SEQUENCE_INVITE;
+        this.callState = 0;
+        this.callMode = SIPStack.SIP_CALLMODE_BASIC;
+        this.callTime_TI = new Date();
+        this.callTime_T0 = new Date();
+        this.callTime_T00 = new Date();
+        this.invitingTimes = 0;
+        this.callTime_T1 = new Date();
+        this.callTime_T2 = new Date();
+        this.callTime_T3 = new Date();
+        this.callTime_T4 = new Date();
+        this.callTime_T40 = new Date();
+        this.callTime_T5 = new Date();
+        this.callTime_T6 = new Date();
+        this.callTime_T7 = new Date();
+        this.callTime_T8 = new Date();
+        this.callTime_T9 = new Date();
+        this.expiresTI = 0;
+        this.expiresT0 = 0;
+        this.expiresT00 = 0;
+        this.expiresT1 = 0;
+        this.expiresT2 = 0;
+        this.expiresT3 = 0;
+        this.expiresT4 = 0;
+        this.expiresT5 = 0;
+        this.expiresT6 = 0;
+        this.expiresT7 = 0;
+        this.expiresT8 = 0;
+        this.expiresT9 = 0;
+        this.sdp = null;
+        this.remoteSdp = null;
+        this.bHolding = false;
+        this.bPending = false;
+        this.bCancelRequest = false;
+        this.bRejectRequest = false;
+        this.bNewcallRequest = false;
+        this.bUpdateRequest = false;
+        this.bAsMaster = false;
+        this.bForwardRequest = false;
+        this.bByedisconnected = false;
+        this.number = "";
+        this.viaBranch = null;
+        this.bResponsebackgroundcall = false;
+        this.bResponsebackgroundcallReady = false;
+        this.responsebackgroundcallTimer = new Date();
+        this.callDirection = SIPStack.SIP_CALLDIRECTION_NONE;
+        this.bDirectcall = SIPStack.bDirectCall;
+        this.hnsOriginatorServiceType = BSSVideo.HNS_SERVICE_NONE;
+        this.hnsReceiverServiceType = BSSVideo.HNS_SERVICE_NONE;
+        BSSVideo.bProgressvideooffer = false;
+        BSSVideo.bCover = true;
+        this.flag = false;
+    }
+
+    public SIPCall(boolean bPending) {
+        if (!SIPStack.bStackLicensed) {
+            System.out.println("라이슨스키를 설정하세요.");
+                    //System.exit(0);
+        }
+        if (SIPStack.SIP_CALLHANDLE_DEBUG)
+            System.out.println("call handle created.");
+        this.updateHeaders = new UPDATEHeaders();
+        this.CSEQ_NUMBER = SIPStack.SIP_SEQUENCE_INVITE;
+        this.callState = 0;
+        this.callMode = SIPStack.SIP_CALLMODE_BASIC;
+        this.callTime_TI = new Date();
+        this.callTime_T0 = new Date();
+        this.callTime_T00 = new Date();
+        this.invitingTimes = 0;
+        this.callTime_T1 = new Date();
+        this.callTime_T2 = new Date();
+        this.callTime_T3 = new Date();
+        this.callTime_T4 = new Date();
+        this.callTime_T40 = new Date();
+        this.callTime_T5 = new Date();
+        this.callTime_T6 = new Date();
+        this.callTime_T7 = new Date();
+        this.callTime_T8 = new Date();
+        this.callTime_T9 = new Date();
+        this.expiresTI = 0;
+        this.expiresT0 = 0;
+        this.expiresT00 = 0;
+        this.expiresT1 = 0;
+        this.expiresT2 = 0;
+        this.expiresT3 = 0;
+        this.expiresT4 = 0;
+        this.expiresT5 = 0;
+        this.expiresT6 = 0;
+        this.expiresT7 = 0;
+        this.expiresT8 = 0;
+        this.expiresT9 = 0;
+        this.sdp = null;
+        this.remoteSdp = null;
+        this.bHolding = false;
+        this.bCancelRequest = false;
+        this.bRejectRequest = false;
+        this.bNewcallRequest = false;
+        this.bUpdateRequest = false;
+        this.bAsMaster = false;
+        this.bForwardRequest = false;
+        this.bByedisconnected = false;
+        this.bResponsebackgroundcall = false;
+        this.bResponsebackgroundcallReady = false;
+        this.responsebackgroundcallTimer = new Date();
+        this.number = "";
+        this.viaBranch = null;
+        bPending = bPending;
+        this.bDirectcall = SIPStack.bDirectCall;
+        this.hnsOriginatorServiceType = BSSVideo.HNS_SERVICE_NONE;
+        this.hnsReceiverServiceType = BSSVideo.HNS_SERVICE_NONE;
+        BSSVideo.bProgressvideooffer = false;
+        BSSVideo.bCover = true;
+        this.flag = false;
+    }
+
+    public void resetCall() {
+        if (SIPStack.SIP_CALLHANDLE_DEBUG) {
+            System.out.println("call handle reset.");
+            SIPStack.printAudioRtpPortInfo();
+        }
+        this.commandLine = null;
+        this.viaH = null;
+        this.viaArray = null;
+        this.routeH = null;
+        this.routeArray = null;
+        this.recordrouteH = null;
+        this.recordrouteArray = null;
+        this.maxforwardH = null;
+        this.contactH = null;
+        this.toH = null;
+        this.fromH = null;
+        this.callidH = null;
+        this.cseqH = null;
+        this.expiresH = null;
+        this.allowH = null;
+        this.useragentH = "User-Agent: KwangHaeSoft SmartSip release 0100o";
+        this.remoteuseragentH = null;
+        this.contentlengthH = null;
+        this.contenttypeH = null;
+        this.authorizationINVITEH = null;
+        this.authorizationCANCELH = null;
+        this.authorizationBYEH = null;
+        this.authorizationACKH = null;
+        this.passertedidentityH = null;
+        this.serverIp = null;
+        this.serverPort = 5060;
+        this.serverDomain = null;
+        this.remoteIp = null;
+        this.remotePort = 5060;
+        this.remoteContactIp = null;
+        this.remoteContactPort = 5060;
+        this.remoteContactUri = null;
+        this.localIp = null;
+        this.localPort = 5060;
+        this.id = null;
+        this.cid = null;
+        this.authid = null;
+        this.authpassword = null;
+        this.fromTag = null;
+        this.toTag = null;
+        this.fromHeaderValue = null;
+        this.toHeaderValue = null;
+        this.callId = null;
+        this.dnis = null;
+        this.CSEQ_NUMBER = SIPStack.SIP_SEQUENCE_INVITE;
+        this.callState = 0;
+        this.callMode = SIPStack.SIP_CALLMODE_BASIC;
+        this.callTime_TI = new Date();
+        this.callTime_T0 = new Date();
+        this.callTime_T00 = new Date();
+        this.invitingTimes = 0;
+        this.callTime_T1 = new Date();
+        this.callTime_T2 = new Date();
+        this.callTime_T3 = new Date();
+        this.callTime_T4 = new Date();
+        this.callTime_T40 = new Date();
+        this.callTime_T5 = new Date();
+        this.callTime_T6 = new Date();
+        this.callTime_T7 = new Date();
+        this.callTime_T8 = new Date();
+        this.callTime_T9 = new Date();
+        this.expiresTI = 0;
+        this.expiresT0 = 0;
+        this.expiresT00 = 0;
+        this.expiresT1 = 0;
+        this.expiresT2 = 0;
+        this.expiresT3 = 0;
+        this.expiresT4 = 0;
+        this.expiresT5 = 0;
+        this.expiresT6 = 0;
+        this.expiresT7 = 0;
+        this.expiresT8 = 0;
+        this.expiresT9 = 0;
+        if (this.sdp != null && this.sdp.flag && this.sdp.audioM != null)
+            SIPStack.freeAudioRtpPort(this.sdp.audioM.mediaPort);
+        this.sdp = null;
+        this.remoteSdp = null;
+        this.message = null;
+        this.bHolding = false;
+        this.bPending = false;
+        this.bCancelRequest = false;
+        this.bRejectRequest = false;
+        this.bNewcallRequest = false;
+        this.bUpdateRequest = false;
+        this.bAsMaster = false;
+        this.bForwardRequest = false;
+        this.bByedisconnected = false;
+        this.bResponsebackgroundcall = false;
+        this.bResponsebackgroundcallReady = false;
+        this.responsebackgroundcallTimer = new Date();
+        this.number = "";
+        this.viaBranch = null;
+        this.callDirection = SIPStack.SIP_CALLDIRECTION_NONE;
+        this.bDirectcall = SIPStack.bDirectCall;
+        this.hnsOriginatorServiceType = BSSVideo.HNS_SERVICE_NONE;
+        this.hnsReceiverServiceType = BSSVideo.HNS_SERVICE_NONE;
+        BSSVideo.bProgressvideooffer = false;
+        BSSVideo.bCover = true;
+        this.flag = false;
+        SIPStack.exceptionCountAtCurrentCall = 0;
+        System.gc();
+    }
+
+    public void initializeRedirectCall() {
+        if (SIPStack.SIP_CALLHANDLE_DEBUG)
+            System.out.println("redirect call handle initialize.");
+        this.viaH = null;
+        this.viaArray = null;
+        this.routeH = null;
+        this.routeArray = null;
+        this.recordrouteH = null;
+        this.recordrouteArray = null;
+        this.remoteContactIp = null;
+        this.remoteContactPort = 5060;
+        this.remoteContactUri = null;
+        this.callId = null;
+        this.authorizationINVITEH = null;
+        this.authorizationCANCELH = null;
+        this.authorizationBYEH = null;
+        this.authorizationACKH = null;
+        this.viaBranch = null;
+        this.callState = 0;
+        this.callMode = SIPStack.SIP_CALLMODE_BASIC;
+        this.callTime_TI = new Date();
+        this.callTime_T0 = new Date();
+        this.callTime_T00 = new Date();
+        this.invitingTimes = 0;
+        this.callTime_T1 = new Date();
+        this.callTime_T2 = new Date();
+        this.callTime_T3 = new Date();
+        this.callTime_T4 = new Date();
+        this.callTime_T40 = new Date();
+        this.callTime_T5 = new Date();
+        this.callTime_T6 = new Date();
+        this.callTime_T7 = new Date();
+        this.callTime_T8 = new Date();
+        this.callTime_T9 = new Date();
+        this.expiresTI = 0;
+        this.expiresT0 = 0;
+        this.expiresT00 = 0;
+        this.expiresT1 = 0;
+        this.expiresT2 = 0;
+        this.expiresT3 = 0;
+        this.expiresT4 = 0;
+        this.expiresT5 = 0;
+        this.expiresT6 = 0;
+        this.expiresT7 = 0;
+        this.expiresT8 = 0;
+        this.expiresT9 = 0;
+        if (this.sdp != null && this.sdp.flag && this.sdp.audioM != null)
+            SIPStack.freeAudioRtpPort(this.sdp.audioM.mediaPort);
+        this.sdp = null;
+        this.remoteSdp = null;
+        this.message = null;
+        this.bHolding = false;
+        this.bPending = false;
+        this.bCancelRequest = false;
+        this.bRejectRequest = false;
+        this.bNewcallRequest = false;
+        this.bUpdateRequest = false;
+        this.bAsMaster = false;
+        this.bForwardRequest = false;
+        this.bByedisconnected = false;
+        this.bResponsebackgroundcall = false;
+        this.bResponsebackgroundcallReady = false;
+        this.responsebackgroundcallTimer = new Date();
+        this.number = "";
+        this.viaBranch = null;
+        this.callDirection = SIPStack.SIP_CALLDIRECTION_NONE;
+        this.bDirectcall = SIPStack.bDirectCall;
+        this.hnsOriginatorServiceType = BSSVideo.HNS_SERVICE_NONE;
+        this.hnsReceiverServiceType = BSSVideo.HNS_SERVICE_NONE;
+        BSSVideo.bProgressvideooffer = false;
+        BSSVideo.bCover = true;
+    }
+
+    public boolean activeCallHandle(String id, String cid, String authid, String authpassword, String number, String serverIp, int serverPort, String serverDomain, String localIp, int localPort) {
+        if (this.flag)
+            return false;
+        resetCall();
+        this.flag = true;
+        if (SIPStack.SIP_CALLHANDLE_DEBUG)
+            System.out.println("call handle activated.");
+        this.id = localIp;
+        this.cid = localIp;
+        this.authid = authid;
+        this.authpassword = authpassword;
+        this.dnis = number;
+        this.serverIp = serverIp;
+        this.serverPort = serverPort;
+        this.serverDomain = serverDomain;
+        this.remoteIp = serverIp;
+        this.remotePort = serverPort;
+        this.localIp = localIp;
+        this.localPort = localPort;
+        this.callTime_TI = new Date();
+        this.callTime_T0 = new Date();
+        this.callTime_T00 = new Date();
+        this.invitingTimes = 0;
+        this.callTime_T1 = new Date();
+        this.callTime_T2 = new Date();
+        this.callTime_T3 = new Date();
+        this.callTime_T4 = new Date();
+        this.callTime_T40 = new Date();
+        this.callTime_T5 = new Date();
+        this.callTime_T6 = new Date();
+        this.callTime_T7 = new Date();
+        this.callTime_T8 = new Date();
+        this.callTime_T9 = new Date();
+        this.expiresTI = 0;
+        this.expiresT0 = 0;
+        this.expiresT00 = 0;
+        this.expiresT1 = 0;
+        this.expiresT2 = 0;
+        this.expiresT3 = 0;
+        this.expiresT4 = 0;
+        this.expiresT5 = 0;
+        this.expiresT6 = 0;
+        this.expiresT7 = 0;
+        this.expiresT8 = 0;
+        this.expiresT9 = 0;
+        this.hnsOriginatorServiceType = BSSVideo.HNS_SERVICE_NONE;
+        this.hnsReceiverServiceType = BSSVideo.HNS_SERVICE_NONE;
+        BSSVideo.bProgressvideooffer = false;
+        BSSVideo.bCover = true;
+        return true;
+    }
+
+    public boolean activePendingCallHandle(String id, String cid, String authid, String authpassword, String number, String serverIp, int serverPort, String serverDomain, String localIp, int localPort) {
+        if (this.flag)
+            return false;
+        resetCall();
+        this.flag = true;
+        if (SIPStack.SIP_CALLHANDLE_DEBUG)
+            System.out.println("conference call activated.");
+        this.id = id;
+        this.cid = cid;
+        this.authid = authid;
+        this.authpassword = authpassword;
+        this.dnis = number;
+        this.serverIp = serverIp;
+        this.serverPort = serverPort;
+        this.serverDomain = serverDomain;
+        this.remoteIp = serverIp;
+        this.remotePort = serverPort;
+        this.localIp = localIp;
+        this.localPort = localPort;
+        this.bPending = true;
+        this.callTime_TI = new Date();
+        this.callTime_T0 = new Date();
+        this.callTime_T00 = new Date();
+        this.invitingTimes = 0;
+        this.callTime_T1 = new Date();
+        this.callTime_T2 = new Date();
+        this.callTime_T3 = new Date();
+        this.callTime_T4 = new Date();
+        this.callTime_T40 = new Date();
+        this.callTime_T5 = new Date();
+        this.callTime_T6 = new Date();
+        this.callTime_T7 = new Date();
+        this.callTime_T8 = new Date();
+        this.callTime_T9 = new Date();
+        this.expiresTI = 0;
+        this.expiresT0 = 0;
+        this.expiresT00 = 0;
+        this.expiresT1 = 0;
+        this.expiresT2 = 0;
+        this.expiresT3 = 0;
+        this.expiresT4 = 0;
+        this.expiresT5 = 0;
+        this.expiresT6 = 0;
+        this.expiresT7 = 0;
+        this.expiresT8 = 0;
+        this.expiresT9 = 0;
+        this.hnsOriginatorServiceType = BSSVideo.HNS_SERVICE_NONE;
+        this.hnsReceiverServiceType = BSSVideo.HNS_SERVICE_NONE;
+        BSSVideo.bProgressvideooffer = false;
+        BSSVideo.bCover = true;
+        return true;
+    }
+
+    public boolean constructHeaders(String message, String remoteIp, int remotePort) {
+        if (message == null || message.length() == 0)
+            return false;
+        this.viaH = null;
+        this.viaArray = new StringBuffer();
+        this.routeH = null;
+        this.routeArray = new StringBuffer();
+        this.recordrouteH = null;
+        this.recordrouteArray = new StringBuffer();
+        this.message = message;
+        StringTokenizer tokenArray = new StringTokenizer(message, SIPStack.SIP_LINE_END, true);
+        while (tokenArray.hasMoreTokens()) {
+            String token = tokenArray.nextToken().trim();
+            if (token.length() <= 0 ||
+                    token.compareTo("\r") == 0 ||
+                    token.compareTo("\n") == 0)
+                continue;
+            if (token.startsWith("From: ")) {
+                this.fromH = token;
+                this.fromHeaderValue = token.substring(6);
+                continue;
+            }
+            if (token.startsWith("f: ")) {
+                this.fromH = token;
+                this.fromHeaderValue = token.substring(3);
+                continue;
+            }
+            if (token.startsWith("To: ")) {
+                this.toH = token;
+                if (this.toH.indexOf("tag=") < 0) {
+                    this.toTag = Long.toString((new Date()).getTime());
+                    this.toH = String.valueOf(token) + ";tag=" + this.toTag;
+                    this.toHeaderValue = String.valueOf(token.substring(4)) + ";tag=" + this.toTag;
+                    continue;
+                }
+                this.toHeaderValue = token.substring(4);
+                continue;
+            }
+            if (token.startsWith("t: ")) {
+                this.toH = token;
+                if (this.toH.indexOf("tag=") < 0) {
+                    this.toTag = Long.toString((new Date()).getTime());
+                    this.toH = String.valueOf(token) + ";tag=" + this.toTag;
+                    this.toHeaderValue = String.valueOf(token.substring(3)) + ";tag=" + this.toTag;
+                    continue;
+                }
+                this.toHeaderValue = token.substring(3);
+                continue;
+            }
+            if (token.startsWith("Via: ")) {
+                if (this.viaH == null) {
+                    this.viaH = token;
+                    if (token.indexOf(";received=") < 0) {
+                        String branch = "";
+                        int index = token.indexOf(";branch=");
+                        if (index > 0)
+                            branch = token.substring(index + 8);
+                        if (branch != null && branch.length() > 0) {
+                            index = branch.indexOf(";");
+                            if (index > 0) {
+                                this.viaBranch = branch.substring(0, index);
+                            } else {
+                                this.viaBranch = branch;
+                            }
+                        } else {
+                            this.viaBranch = "";
+                        }
+                        index = token.indexOf(";branch=");
+                        if (index > 0) {
+                            this.viaH = token.substring(0, index);
+                        } else {
+                            this.viaH = token;
+                        }
+                        index = this.viaH.indexOf(";rport=");
+                        if (index > 0)
+                            this.viaH = this.viaH.substring(0, index);
+                        this.viaH = String.valueOf(this.viaH) + ";received=" + remoteIp + ";rport=" + remotePort + ";branch=" + this.viaBranch;
+                    }
+                    this.viaArray.append(String.valueOf(this.viaH) + SIPStack.SIP_LINE_END);
+                    continue;
+                }
+                this.viaArray.append(String.valueOf(token) + SIPStack.SIP_LINE_END);
+                continue;
+            }
+            if (token.startsWith("v: ")) {
+                if (this.viaH == null) {
+                    this.viaH = token;
+                    if (token.indexOf(";received=") < 0) {
+                        String branch = "";
+                        int index = token.indexOf(";branch=");
+                        if (index > 0)
+                            branch = token.substring(index + 8);
+                        if (branch != null && branch.length() > 0) {
+                            index = branch.indexOf(";");
+                            if (index > 0) {
+                                this.viaBranch = branch.substring(0, index);
+                            } else {
+                                this.viaBranch = branch;
+                            }
+                        } else {
+                            this.viaBranch = branch;
+                        }
+                        index = token.indexOf(";branch=");
+                        if (index > 0) {
+                            this.viaH = token.substring(0, index);
+                        } else {
+                            this.viaH = token;
+                        }
+                        index = this.viaH.indexOf(";rport=");
+                        if (index > 0)
+                            this.viaH = this.viaH.substring(0, index);
+                        this.viaH = String.valueOf(this.viaH) + ";received=" + remoteIp + ";rport=" + remotePort + ";branch=" + this.viaBranch;
+                    }
+                    this.viaArray.append(String.valueOf(this.viaH) + SIPStack.SIP_LINE_END);
+                    continue;
+                }
+                this.viaArray.append(String.valueOf(token) + SIPStack.SIP_LINE_END);
+                continue;
+            }
+            if (token.startsWith("Record-Route: ")) {
+                if (this.recordrouteH == null) {
+                    this.routeH = null;
+                    this.routeArray = new StringBuffer();
+                    this.recordrouteH = token;
+                    this.recordrouteArray.append(String.valueOf(this.recordrouteH) + SIPStack.SIP_LINE_END);
+                    this.routeArray.append(String.valueOf(token.substring(7)) + SIPStack.SIP_LINE_END);
+                    continue;
+                }
+                this.recordrouteArray.append(String.valueOf(token) + SIPStack.SIP_LINE_END);
+                this.routeArray.append(String.valueOf(token.substring(7)) + SIPStack.SIP_LINE_END);
+                continue;
+            }
+            if (token.startsWith("Contact: ")) {
+                this.contactH = token;
+                if (token.length() > 0) {
+                    int iS = 0;
+                    iS = token.indexOf("sip:");
+                    if (iS > 0) {
+                        String str = null;
+                        int iE = 0;
+                        iE = token.indexOf(">", iS);
+                        if (iE > 0) {
+                            str = token.substring(iS, iE);
+                        } else {
+                            str = token.substring(iS);
+                        }
+                        iE = str.indexOf(";");
+                        if (iE > 0)
+                            str = str.substring(0, iE);
+                        iE = str.indexOf(";");
+                        if (iE > 0)
+                            str = str.substring(0, iE);
+                        iE = str.indexOf(" ");
+                        if (iE > 0)
+                            str = str.substring(0, iE);
+                        if (str.length() > 0)
+                            this.remoteContactUri = str;
+                        if (str.length() > 0) {
+                            iS = str.indexOf("@");
+                            if (iS > 0) {
+                                str = str.substring(iS + 1);
+                            } else {
+                                str = str.substring(4);
+                            }
+                            int iM = str.indexOf(":", iS);
+                            if (iM < 0) {
+                                this.remoteContactIp = str;
+                                this.remoteContactPort = 5060;
+                                continue;
+                            }
+                            this.remoteContactIp = str.substring(0, iM).trim();
+                            this.remoteContactPort = Integer.parseInt(str.substring(iM + 1).trim());
+                        }
+                    }
+                }
+                continue;
+            }
+            if (token.startsWith("m: ")) {
+                this.contactH = token;
+                if (token.length() > 0) {
+                    int iS = 0;
+                    iS = token.indexOf("sip:");
+                    if (iS > 0) {
+                        String str = null;
+                        int iE = 0;
+                        iE = token.indexOf(">", iS);
+                        if (iE > 0) {
+                            str = token.substring(iS, iE);
+                        } else {
+                            str = token.substring(iS);
+                        }
+                        iE = str.indexOf(";");
+                        if (iE > 0)
+                            str = str.substring(0, iE);
+                        iE = str.indexOf(";");
+                        if (iE > 0)
+                            str = str.substring(0, iE);
+                        iE = str.indexOf(" ");
+                        if (iE > 0)
+                            str = str.substring(0, iE);
+                        if (str.length() > 0)
+                            this.remoteContactUri = str;
+                        if (str.length() > 0) {
+                            iS = str.indexOf("@");
+                            if (iS > 0) {
+                                str = str.substring(iS + 1);
+                            } else {
+                                str = str.substring(4);
+                            }
+                            int iM = str.indexOf(":", iS);
+                            if (iM < 0) {
+                                this.remoteContactIp = str;
+                                this.remoteContactPort = 5060;
+                                continue;
+                            }
+                            this.remoteContactIp = str.substring(0, iM).trim();
+                            this.remoteContactPort = Integer.parseInt(str.substring(iM + 1).trim());
+                        }
+                    }
+                }
+                continue;
+            }
+            if (token.startsWith("Call-ID: ")) {
+                this.callidH = token;
+                this.callId = token.substring(9).trim();
+                if (this.callId.startsWith(BSSVideo.HNS_PREFIX_LOBBY)) {
+                    this.hnsOriginatorServiceType = BSSVideo.HNS_SERVICE_LOBBY;
+                    if (this.callId.endsWith(BSSVideo.HNS_POSTFIX_GUARD)) {
+                        this.hnsReceiverServiceType = BSSVideo.HNS_SERVICE_GUARD;
+                        BSSVideo.bProgressvideooffer = true;
+                        continue;
+                    }
+                    if (this.callId.endsWith(BSSVideo.HNS_POSTFIX_NEIGHBOR)) {
+                        this.hnsReceiverServiceType = BSSVideo.HNS_SERVICE_NEIGHBOR;
+                        BSSVideo.bProgressvideooffer = true;
+                        continue;
+                    }
+                    this.hnsReceiverServiceType = BSSVideo.HNS_SERVICE_NONE;
+                    BSSVideo.bProgressvideooffer = false;
+                    continue;
+                }
+                if (this.callId.startsWith(BSSVideo.HNS_PREFIX_GUARD)) {
+                    this.hnsOriginatorServiceType = BSSVideo.HNS_SERVICE_GUARD;
+                    if (this.callId.endsWith(BSSVideo.HNS_POSTFIX_GUARD)) {
+                        this.hnsReceiverServiceType = BSSVideo.HNS_SERVICE_GUARD;
+                        BSSVideo.bProgressvideooffer = true;
+                        continue;
+                    }
+                    if (this.callId.endsWith(BSSVideo.HNS_POSTFIX_LOBBY)) {
+                        this.hnsReceiverServiceType = BSSVideo.HNS_SERVICE_LOBBY;
+                        BSSVideo.bProgressvideooffer = true;
+                        continue;
+                    }
+                    if (this.callId.endsWith(BSSVideo.HNS_POSTFIX_NEIGHBOR)) {
+                        this.hnsReceiverServiceType = BSSVideo.HNS_SERVICE_NEIGHBOR;
+                        BSSVideo.bProgressvideooffer = true;
+                        continue;
+                    }
+                    this.hnsReceiverServiceType = BSSVideo.HNS_SERVICE_NONE;
+                    BSSVideo.bProgressvideooffer = false;
+                    continue;
+                }
+                if (this.callId.startsWith(BSSVideo.HNS_PREFIX_NEIGHBOR)) {
+                    this.hnsOriginatorServiceType = BSSVideo.HNS_SERVICE_NEIGHBOR;
+                    if (this.callId.endsWith(BSSVideo.HNS_POSTFIX_GUARD)) {
+                        this.hnsReceiverServiceType = BSSVideo.HNS_SERVICE_GUARD;
+                        BSSVideo.bProgressvideooffer = true;
+                        continue;
+                    }
+                    if (this.callId.endsWith(BSSVideo.HNS_POSTFIX_NEIGHBOR)) {
+                        this.hnsReceiverServiceType = BSSVideo.HNS_SERVICE_NEIGHBOR;
+                        BSSVideo.bProgressvideooffer = false;
+                        continue;
+                    }
+                    this.hnsReceiverServiceType = BSSVideo.HNS_SERVICE_NONE;
+                    BSSVideo.bProgressvideooffer = false;
+                    continue;
+                }
+                this.hnsOriginatorServiceType = BSSVideo.HNS_SERVICE_NONE;
+                this.hnsReceiverServiceType = BSSVideo.HNS_SERVICE_NONE;
+                BSSVideo.bProgressvideooffer = false;
+                continue;
+            }
+            if (token.startsWith("i: ")) {
+                this.callidH = token;
+                this.callId = token.substring(3).trim();
+                if (this.callId.startsWith(BSSVideo.HNS_PREFIX_LOBBY)) {
+                    this.hnsOriginatorServiceType = BSSVideo.HNS_SERVICE_LOBBY;
+                    if (this.callId.endsWith(BSSVideo.HNS_POSTFIX_GUARD)) {
+                        this.hnsReceiverServiceType = BSSVideo.HNS_SERVICE_GUARD;
+                        BSSVideo.bProgressvideooffer = true;
+                        continue;
+                    }
+                    if (this.callId.endsWith(BSSVideo.HNS_POSTFIX_NEIGHBOR)) {
+                        this.hnsReceiverServiceType = BSSVideo.HNS_SERVICE_NEIGHBOR;
+                        BSSVideo.bProgressvideooffer = true;
+                        continue;
+                    }
+                    this.hnsReceiverServiceType = BSSVideo.HNS_SERVICE_NONE;
+                    BSSVideo.bProgressvideooffer = false;
+                    continue;
+                }
+                if (this.callId.startsWith(BSSVideo.HNS_PREFIX_GUARD)) {
+                    this.hnsOriginatorServiceType = BSSVideo.HNS_SERVICE_GUARD;
+                    if (this.callId.endsWith(BSSVideo.HNS_POSTFIX_GUARD)) {
+                        this.hnsReceiverServiceType = BSSVideo.HNS_SERVICE_GUARD;
+                        BSSVideo.bProgressvideooffer = true;
+                        continue;
+                    }
+                    if (this.callId.endsWith(BSSVideo.HNS_POSTFIX_LOBBY)) {
+                        this.hnsReceiverServiceType = BSSVideo.HNS_SERVICE_LOBBY;
+                        BSSVideo.bProgressvideooffer = true;
+                        continue;
+                    }
+                    if (this.callId.endsWith(BSSVideo.HNS_POSTFIX_NEIGHBOR)) {
+                        this.hnsReceiverServiceType = BSSVideo.HNS_SERVICE_NEIGHBOR;
+                        BSSVideo.bProgressvideooffer = true;
+                        continue;
+                    }
+                    this.hnsReceiverServiceType = BSSVideo.HNS_SERVICE_NONE;
+                    BSSVideo.bProgressvideooffer = false;
+                    continue;
+                }
+                if (this.callId.startsWith(BSSVideo.HNS_PREFIX_NEIGHBOR)) {
+                    this.hnsOriginatorServiceType = BSSVideo.HNS_SERVICE_NEIGHBOR;
+                    if (this.callId.endsWith(BSSVideo.HNS_POSTFIX_GUARD)) {
+                        this.hnsReceiverServiceType = BSSVideo.HNS_SERVICE_GUARD;
+                        BSSVideo.bProgressvideooffer = true;
+                        continue;
+                    }
+                    if (this.callId.endsWith(BSSVideo.HNS_POSTFIX_NEIGHBOR)) {
+                        this.hnsReceiverServiceType = BSSVideo.HNS_SERVICE_NEIGHBOR;
+                        BSSVideo.bProgressvideooffer = false;
+                        continue;
+                    }
+                    this.hnsReceiverServiceType = BSSVideo.HNS_SERVICE_NONE;
+                    BSSVideo.bProgressvideooffer = false;
+                    continue;
+                }
+                this.hnsOriginatorServiceType = BSSVideo.HNS_SERVICE_NONE;
+                this.hnsReceiverServiceType = BSSVideo.HNS_SERVICE_NONE;
+                BSSVideo.bProgressvideooffer = false;
+                continue;
+            }
+            if (token.startsWith("CSeq: ")) {
+                this.cseqH = token;
+                StringTokenizer fieldArray = new StringTokenizer(token, " ", true);
+                int tokenCount = 0;
+                while (fieldArray.hasMoreTokens()) {
+                    String fieldtoken = fieldArray.nextToken();
+                    if (fieldtoken.length() > 0 && fieldtoken.compareTo(" ") != 0) {
+                        tokenCount++;
+                        if (tokenCount == 2) {
+                            this.CSEQ_NUMBER = Integer.parseInt(fieldtoken);
+                            break;
+                        }
+                    }
+                }
+                continue;
+            }
+            if (token.startsWith("Content-Type: ")) {
+                this.contenttypeH = token;
+                continue;
+            }
+            if (token.startsWith("c: ")) {
+                this.contenttypeH = token;
+                continue;
+            }
+            if (token.startsWith("Content-Length: ")) {
+                this.contentlengthH = token;
+                continue;
+            }
+            if (token.startsWith("l: ")) {
+                this.contentlengthH = token;
+                continue;
+            }
+            if (token.startsWith("User-Agent: ")) {
+                this.remoteuseragentH = token;
+                this.useragentH = "User-Agent: KwangHaeSoft SmartSip release 0100o";
+                continue;
+            }
+            if (token.startsWith("P-Asserted-Identity: "))
+                this.passertedidentityH = token;
+        }
+        this.allowH = "Allow: INVITE, ACK, CANCEL, OPTIONS, BYE, REFER, NOTIFY, MESSAGE, SUBSCRIBE, INFO";
+        this.maxforwardH = "Max-Forwards: 70";
+        int audioport = SIPStack.getFreeAudioRtpPort();
+        if (audioport > 0)
+            constructSdp();
+        if (this.sdp != null && this.sdp.flag) {
+            this.sdp.setMediaPort(SIPStack.SIP_MEDIATYPE_AUDIO, audioport);
+            if (SIPStack.PRIMARY_CODEC_AUDIO == SIPStack.SIP_CODEC_G711U) {
+                this.sdp.setCodec(
+                        SIPStack.SIP_MEDIATYPE_AUDIO,
+                        SIPStack.SIP_CODEC_G711U,
+                        "PCMU/8000");
+                this.sdp.setCodec(
+                        SIPStack.SIP_MEDIATYPE_AUDIO,
+                        SIPStack.SIP_CODEC_G711A,
+                        "PCMA/8000");
+            } else {
+                this.sdp.setCodec(
+                        SIPStack.SIP_MEDIATYPE_AUDIO,
+                        SIPStack.SIP_CODEC_G711A,
+                        "PCMA/8000");
+                this.sdp.setCodec(
+                        SIPStack.SIP_MEDIATYPE_AUDIO,
+                        SIPStack.SIP_CODEC_G711U,
+                        "PCMU/8000");
+            }
+            this.sdp.setCodec(
+                    SIPStack.SIP_MEDIATYPE_AUDIO,
+                    RFC2833.payloadType,
+                    "telephone-event/8000");
+            this.sdp.setFmtpDescribe(SIPStack.SIP_MEDIATYPE_AUDIO, RFC2833.payloadType, "0-15");
+        }
+        if (parseRemoteSdp(message))
+            if (this.remoteSdp != null &&
+                    this.remoteSdp.flag)
+                if (this.remoteSdp.audioM != null &&
+                        this.sdp != null && this.sdp.flag && this.sdp.audioM != null &&
+                        this.remoteSdp.audioM.flow != null &&
+                        this.remoteSdp.audioM.flow.length() > 0)
+                    if (this.remoteSdp.audioM.flow.compareTo("sendrecv") == 0) {
+                        this.sdp.audioM.setFlow("sendrecv");
+                    } else if (this.remoteSdp.audioM.flow.compareTo("sendonly") == 0) {
+                        this.sdp.audioM.setFlow("recvonly");
+                    } else if (this.remoteSdp.audioM.flow.compareTo("recvonly") == 0) {
+                        this.sdp.audioM.setFlow("sendonly");
+                    }
+        negotiateAudioCodec();
+        return true;
+    }
+
+    public boolean constructUPDATEHeaders(String message, String remoteIp, int remotePort) {
+        if (message == null || message.length() == 0)
+            return false;
+        resetUpdateheaders();
+        setUpdateheaders();
+        this.viaH = null;
+        this.viaArray = new StringBuffer();
+        this.routeH = null;
+        this.routeArray = new StringBuffer();
+        this.recordrouteH = null;
+        this.recordrouteArray = new StringBuffer();
+        this.message = message;
+        StringTokenizer tokenArray = new StringTokenizer(message, SIPStack.SIP_LINE_END, true);
+        while (tokenArray.hasMoreTokens()) {
+            String token = tokenArray.nextToken().trim();
+            if (token.length() <= 0 ||
+                    token.compareTo("\r") == 0 ||
+                    token.compareTo("\n") == 0)
+                continue;
+            if (token.startsWith("From: ")) {
+                this.fromH = token;
+                int iS = this.fromH.indexOf(";tag=");
+                if (iS > 0) {
+                    String str = null;
+                    int iE = this.fromH.indexOf(";", iS + 5);
+                    if (iE >= 0) {
+                        if (iE > iS + 5) {
+                            str = this.fromH.substring(iS + 5, iE);
+                        } else {
+                            str = "";
+                        }
+                    } else {
+                        str = this.fromH.substring(iS + 5);
+                    }
+                    if (str != null && str.length() > 0)
+                        this.fromTag = str.trim();
+                }
+                this.fromHeaderValue = token.substring(6);
+                System.out.println("FROM TAG:" + this.fromTag);
+                continue;
+            }
+            if (token.startsWith("f: ")) {
+                this.fromH = token;
+                int iS = this.fromH.indexOf(";tag=");
+                if (iS > 0) {
+                    String str = null;
+                    int iE = this.fromH.indexOf(";", iS + 5);
+                    if (iE >= 0) {
+                        if (iE > iS + 5) {
+                            str = this.fromH.substring(iS + 5, iE);
+                        } else {
+                            str = "";
+                        }
+                    } else {
+                        str = this.fromH.substring(iS + 5);
+                    }
+                    if (str != null && str.length() > 0)
+                        this.fromTag = str.trim();
+                }
+                this.fromHeaderValue = token.substring(3);
+                System.out.println("FROM TAG:" + this.fromTag);
+                continue;
+            }
+            if (token.startsWith("To: ")) {
+                this.toH = token;
+                int iS = this.toH.indexOf(";tag=");
+                if (iS > 0) {
+                    String str = null;
+                    int iE = this.toH.indexOf(";", iS + 5);
+                    if (iE >= 0) {
+                        if (iE > iS + 5) {
+                            str = this.toH.substring(iS + 5, iE);
+                        } else {
+                            str = "";
+                        }
+                    } else {
+                        str = this.toH.substring(iS + 5);
+                    }
+                    if (str != null && str.length() > 0)
+                        this.toTag = str.trim();
+                }
+                this.toHeaderValue = token.substring(4);
+                System.out.println("TO TAG:" + this.toTag);
+                continue;
+            }
+            if (token.startsWith("To: ")) {
+                this.toH = token;
+                int iS = this.toH.indexOf(";tag=");
+                if (iS > 0) {
+                    String str = null;
+                    int iE = this.toH.indexOf(";", iS + 5);
+                    if (iE >= 0) {
+                        if (iE > iS + 5) {
+                            str = this.toH.substring(iS + 5, iE);
+                        } else {
+                            str = "";
+                        }
+                    } else {
+                        str = this.toH.substring(iS + 5);
+                    }
+                    if (str != null && str.length() > 0)
+                        this.toTag = str.trim();
+                }
+                this.toHeaderValue = token.substring(3);
+                System.out.println("TO TAG:" + this.toTag);
+                continue;
+            }
+            if (token.startsWith("Via: ")) {
+                if (this.viaH == null) {
+                    this.viaH = token;
+                    if (token.indexOf(";received=") < 0) {
+                        String branch = "";
+                        int index = token.indexOf(";branch=");
+                        if (index > 0)
+                            branch = token.substring(index + 8);
+                        if (branch != null && branch.length() > 0) {
+                            index = branch.indexOf(";");
+                            if (index > 0) {
+                                this.viaBranch = branch.substring(0, index);
+                            } else {
+                                this.viaBranch = branch;
+                            }
+                        } else {
+                            this.viaBranch = "";
+                        }
+                        index = token.indexOf(";branch=");
+                        if (index > 0) {
+                            this.viaH = token.substring(0, index);
+                        } else {
+                            this.viaH = token;
+                        }
+                        index = this.viaH.indexOf(";rport=");
+                        if (index > 0)
+                            this.viaH = this.viaH.substring(0, index);
+                        this.viaH = String.valueOf(this.viaH) + ";received=" + remoteIp + ";rport=" + remotePort + ";branch=" + this.viaBranch;
+                    }
+                    this.viaArray.append(String.valueOf(this.viaH) + SIPStack.SIP_LINE_END);
+                    continue;
+                }
+                this.viaArray.append(String.valueOf(token) + SIPStack.SIP_LINE_END);
+                continue;
+            }
+            if (token.startsWith("v: ")) {
+                if (this.viaH == null) {
+                    this.viaH = token;
+                    if (token.indexOf(";received=") < 0) {
+                        String branch = "";
+                        int index = token.indexOf(";branch=");
+                        if (index > 0)
+                            branch = token.substring(index + 8);
+                        if (branch != null && branch.length() > 0) {
+                            index = branch.indexOf(";");
+                            if (index > 0) {
+                                this.viaBranch = branch.substring(0, index);
+                            } else {
+                                this.viaBranch = branch;
+                            }
+                        } else {
+                            this.viaBranch = branch;
+                        }
+                        index = token.indexOf(";branch=");
+                        if (index > 0) {
+                            this.viaH = token.substring(0, index);
+                        } else {
+                            this.viaH = token;
+                        }
+                        index = this.viaH.indexOf(";rport=");
+                        if (index > 0)
+                            this.viaH = this.viaH.substring(0, index);
+                        this.viaH = String.valueOf(this.viaH) + ";received=" + remoteIp + ";rport=" + remotePort + ";branch=" + this.viaBranch;
+                    }
+                    this.viaArray.append(String.valueOf(this.viaH) + SIPStack.SIP_LINE_END);
+                    continue;
+                }
+                this.viaArray.append(String.valueOf(token) + SIPStack.SIP_LINE_END);
+                continue;
+            }
+            if (token.startsWith("Record-Route: ")) {
+                if (this.recordrouteH == null) {
+                    this.routeH = null;
+                    this.routeArray = new StringBuffer();
+                    this.recordrouteH = token;
+                    this.recordrouteArray.append(String.valueOf(this.recordrouteH) + SIPStack.SIP_LINE_END);
+                    this.routeArray.append(String.valueOf(token.substring(7)) + SIPStack.SIP_LINE_END);
+                    continue;
+                }
+                this.recordrouteArray.append(String.valueOf(token) + SIPStack.SIP_LINE_END);
+                this.routeArray.append(String.valueOf(token.substring(7)) + SIPStack.SIP_LINE_END);
+                continue;
+            }
+            if (token.startsWith("Contact: ")) {
+                this.contactH = token;
+                if (token.length() > 0) {
+                    int iS = 0;
+                    iS = token.indexOf("sip:");
+                    if (iS > 0) {
+                        String str = null;
+                        int iE = 0;
+                        iE = token.indexOf(">", iS);
+                        if (iE > 0) {
+                            str = token.substring(iS, iE);
+                        } else {
+                            str = token.substring(iS);
+                        }
+                        iE = str.indexOf(";");
+                        if (iE > 0)
+                            str = str.substring(0, iE);
+                        iE = str.indexOf(";");
+                        if (iE > 0)
+                            str = str.substring(0, iE);
+                        iE = str.indexOf(" ");
+                        if (iE > 0)
+                            str = str.substring(0, iE);
+                        if (str.length() > 0)
+                            this.remoteContactUri = str;
+                        if (str.length() > 0) {
+                            iS = str.indexOf("@");
+                            if (iS > 0) {
+                                str = str.substring(iS + 1);
+                            } else {
+                                str = str.substring(4);
+                            }
+                            int iM = str.indexOf(":", iS);
+                            if (iM < 0) {
+                                this.remoteContactIp = str;
+                                this.remoteContactPort = 5060;
+                                continue;
+                            }
+                            this.remoteContactIp = str.substring(0, iM).trim();
+                            this.remoteContactPort = Integer.parseInt(str.substring(iM + 1).trim());
+                        }
+                    }
+                }
+                continue;
+            }
+            if (token.startsWith("m: ")) {
+                this.contactH = token;
+                if (token.length() > 0) {
+                    int iS = 0;
+                    iS = token.indexOf("sip:");
+                    if (iS > 0) {
+                        String str = null;
+                        int iE = 0;
+                        iE = token.indexOf(">", iS);
+                        if (iE > 0) {
+                            str = token.substring(iS, iE);
+                        } else {
+                            str = token.substring(iS);
+                        }
+                        iE = str.indexOf(";");
+                        if (iE > 0)
+                            str = str.substring(0, iE);
+                        iE = str.indexOf(";");
+                        if (iE > 0)
+                            str = str.substring(0, iE);
+                        iE = str.indexOf(" ");
+                        if (iE > 0)
+                            str = str.substring(0, iE);
+                        if (str.length() > 0)
+                            this.remoteContactUri = str;
+                        if (str.length() > 0) {
+                            iS = str.indexOf("@");
+                            if (iS > 0) {
+                                str = str.substring(iS + 1);
+                            } else {
+                                str = str.substring(4);
+                            }
+                            int iM = str.indexOf(":", iS);
+                            if (iM < 0) {
+                                this.remoteContactIp = str;
+                                this.remoteContactPort = 5060;
+                                continue;
+                            }
+                            this.remoteContactIp = str.substring(0, iM).trim();
+                            this.remoteContactPort = Integer.parseInt(str.substring(iM + 1).trim());
+                        }
+                    }
+                }
+                continue;
+            }
+            if (token.startsWith("Call-ID: ")) {
+                this.callidH = token;
+                this.callId = token.substring(9).trim();
+                continue;
+            }
+            if (token.startsWith("i: ")) {
+                this.callidH = token;
+                this.callId = token.substring(3).trim();
+                continue;
+            }
+            if (token.startsWith("CSeq: ")) {
+                this.cseqH = token;
+                StringTokenizer fieldArray = new StringTokenizer(token, " ", true);
+                int tokenCount = 0;
+                while (fieldArray.hasMoreTokens()) {
+                    String fieldtoken = fieldArray.nextToken();
+                    if (fieldtoken.length() > 0 && fieldtoken.compareTo(" ") != 0) {
+                        tokenCount++;
+                        if (tokenCount == 2) {
+                            this.CSEQ_NUMBER = Integer.parseInt(fieldtoken);
+                            break;
+                        }
+                    }
+                }
+                continue;
+            }
+            if (token.startsWith("Content-Type: ")) {
+                this.contenttypeH = token;
+                continue;
+            }
+            if (token.startsWith("c: ")) {
+                this.contenttypeH = token;
+                continue;
+            }
+            if (token.startsWith("Content-Length: ")) {
+                this.contentlengthH = token;
+                continue;
+            }
+            if (token.startsWith("l: ")) {
+                this.contentlengthH = token;
+                continue;
+            }
+            if (token.startsWith("User-Agent: ")) {
+                this.remoteuseragentH = token;
+                this.useragentH = "User-Agent: KwangHaeSoft SmartSip release 0100o";
+                continue;
+            }
+            if (token.startsWith("P-Asserted-Identity: "))
+                this.passertedidentityH = token;
+        }
+        this.allowH = "Allow: INVITE, ACK, CANCEL, OPTIONS, BYE, REFER, NOTIFY, MESSAGE, SUBSCRIBE, INFO";
+        this.maxforwardH = "Max-Forwards: 70";
+        int audioport = this.updateHeaders.sdp.audioM.mediaPort;
+        if (audioport > 0)
+            constructSdp();
+        if (this.sdp != null && this.sdp.flag) {
+            this.sdp.setMediaPort(SIPStack.SIP_MEDIATYPE_AUDIO, audioport);
+            if (SIPStack.PRIMARY_CODEC_AUDIO == SIPStack.SIP_CODEC_G711U) {
+                this.sdp.setCodec(
+                        SIPStack.SIP_MEDIATYPE_AUDIO,
+                        SIPStack.SIP_CODEC_G711U,
+                        "PCMU/8000");
+                this.sdp.setCodec(
+                        SIPStack.SIP_MEDIATYPE_AUDIO,
+                        SIPStack.SIP_CODEC_G711A,
+                        "PCMA/8000");
+            } else {
+                this.sdp.setCodec(
+                        SIPStack.SIP_MEDIATYPE_AUDIO,
+                        SIPStack.SIP_CODEC_G711A,
+                        "PCMA/8000");
+                this.sdp.setCodec(
+                        SIPStack.SIP_MEDIATYPE_AUDIO,
+                        SIPStack.SIP_CODEC_G711U,
+                        "PCMU/8000");
+            }
+            this.sdp.setCodec(
+                    SIPStack.SIP_MEDIATYPE_AUDIO,
+                    RFC2833.payloadType,
+                    "telephone-event/8000");
+            this.sdp.setFmtpDescribe(SIPStack.SIP_MEDIATYPE_AUDIO, RFC2833.payloadType, "0-15");
+        }
+        if (parseRemoteSdp(message))
+            if (this.remoteSdp != null &&
+                    this.remoteSdp.flag)
+                if (this.remoteSdp.audioM != null &&
+                        this.sdp != null && this.sdp.flag && this.sdp.audioM != null &&
+                        this.remoteSdp.audioM.flow != null &&
+                        this.remoteSdp.audioM.flow.length() > 0)
+                    if (this.remoteSdp.audioM.flow.compareTo("sendrecv") == 0) {
+                        this.sdp.audioM.setFlow("sendrecv");
+                    } else if (this.remoteSdp.audioM.flow.compareTo("sendonly") == 0) {
+                        this.sdp.audioM.setFlow("recvonly");
+                    } else if (this.remoteSdp.audioM.flow.compareTo("recvonly") == 0) {
+                        this.sdp.audioM.setFlow("sendonly");
+                    }
+        negotiateAudioCodec();
+        return true;
+    }
+
+    public void reverseRecordRoute(String message) {
+        if (message == null || message.length() == 0)
+            return;
+        this.recordrouteArray = null;
+        this.routeH = null;
+        StringTokenizer tokenArray = new StringTokenizer(message, SIPStack.SIP_LINE_END, true);
+        while (tokenArray.hasMoreTokens()) {
+            String token = tokenArray.nextToken().trim();
+            if (token.length() <= 0 ||
+                    token.compareTo("\r") == 0 ||
+                    token.compareTo("\n") == 0)
+                continue;
+            if (token.startsWith("Record-Route: ")) {
+                this.routeH = token.substring(7).trim();
+                if (this.routeArray == null) {
+                    this.routeArray = new StringBuffer();
+                    this.routeArray.append(String.valueOf(token.substring(7)) + SIPStack.SIP_LINE_END);
+                    continue;
+                }
+                if (this.routeArray != null && this.routeArray.length() > 0) {
+                    this.routeArray.insert(0, String.valueOf(token.substring(7)) + SIPStack.SIP_LINE_END);
+                    continue;
+                }
+                if (this.routeArray != null)
+                    this.routeArray.append(String.valueOf(token.substring(7)) + SIPStack.SIP_LINE_END);
+                continue;
+            }
+            if (token.startsWith("Contact: ")) {
+                this.contactH = token;
+                if (token.length() > 0) {
+                    int iS = 0;
+                    iS = token.indexOf("sip:");
+                    if (iS > 0) {
+                        String str = null;
+                        int iE = 0;
+                        iE = token.indexOf(">", iS);
+                        if (iE > 0) {
+                            str = token.substring(iS, iE);
+                        } else {
+                            str = token.substring(iS);
+                        }
+                        iE = str.indexOf(";");
+                        if (iE > 0)
+                            str = str.substring(0, iE);
+                        iE = str.indexOf(";");
+                        if (iE > 0)
+                            str = str.substring(0, iE);
+                        iE = str.indexOf(" ");
+                        if (iE > 0)
+                            str = str.substring(0, iE);
+                        if (str.length() > 0)
+                            this.remoteContactUri = str;
+                        if (str.length() > 0) {
+                            iS = str.indexOf("@");
+                            if (iS > 0) {
+                                str = str.substring(iS + 1);
+                            } else {
+                                str = str.substring(4);
+                            }
+                            int iM = str.indexOf(":", iS);
+                            if (iM < 0) {
+                                this.remoteContactIp = str;
+                                this.remoteContactPort = 5060;
+                                continue;
+                            }
+                            this.remoteContactIp = str.substring(0, iM).trim();
+                            this.remoteContactPort = Integer.parseInt(str.substring(iM + 1).trim());
+                        }
+                    }
+                }
+                continue;
+            }
+            if (token.startsWith("m: ")) {
+                this.contactH = token;
+                if (token.length() > 0) {
+                    int iS = 0;
+                    iS = token.indexOf("sip:");
+                    if (iS > 0) {
+                        String str = null;
+                        int iE = 0;
+                        iE = token.indexOf(">", iS);
+                        if (iE > 0) {
+                            str = token.substring(iS, iE);
+                        } else {
+                            str = token.substring(iS);
+                        }
+                        iE = str.indexOf(";");
+                        if (iE > 0)
+                            str = str.substring(0, iE);
+                        iE = str.indexOf(";");
+                        if (iE > 0)
+                            str = str.substring(0, iE);
+                        iE = str.indexOf(" ");
+                        if (iE > 0)
+                            str = str.substring(0, iE);
+                        if (str.length() > 0)
+                            this.remoteContactUri = str;
+                        if (str.length() > 0) {
+                            iS = str.indexOf("@");
+                            if (iS > 0) {
+                                str = str.substring(iS + 1);
+                            } else {
+                                str = str.substring(4);
+                            }
+                            int iM = str.indexOf(":", iS);
+                            if (iM < 0) {
+                                this.remoteContactIp = str;
+                                this.remoteContactPort = 5060;
+                                continue;
+                            }
+                            this.remoteContactIp = str.substring(0, iM).trim();
+                            this.remoteContactPort = Integer.parseInt(str.substring(iM + 1).trim());
+                        }
+                    }
+                }
+            }
+        }
+    }
+
+    public String getViaArray(String message) {
+        if (message == null || message.length() == 0)
+            return null;
+        StringBuffer viaArray = new StringBuffer();
+        String viaH = null;
+        StringTokenizer tokenArray = new StringTokenizer(message, SIPStack.SIP_LINE_END, true);
+        while (tokenArray.hasMoreTokens()) {
+            String token = tokenArray.nextToken().trim();
+            if (token.length() <= 0 ||
+                    token.compareTo("\r") == 0 ||
+                    token.compareTo("\n") == 0)
+                continue;
+            if (token.startsWith("Via: ")) {
+                if (viaH == null) {
+                    viaH = token;
+                    if (token.indexOf(";received=") < 0) {
+                        String branch = "";
+                        int index = token.indexOf(";branch=");
+                        if (index > 0)
+                            branch = token.substring(index + 8);
+                        if (branch != null && branch.length() > 0) {
+                            index = branch.indexOf(";");
+                            if (index > 0) {
+                                this.viaBranch = branch.substring(0, index);
+                            } else {
+                                this.viaBranch = branch;
+                            }
+                        } else {
+                            this.viaBranch = "";
+                        }
+                        index = token.indexOf(";branch=");
+                        if (index > 0) {
+                            viaH = token.substring(0, index);
+                        } else {
+                            viaH = token;
+                        }
+                        index = viaH.indexOf(";rport=");
+                        if (index > 0)
+                            viaH = viaH.substring(0, index);
+                        viaH = String.valueOf(viaH) + ";received=" + this.remoteIp + ";rport=" + this.remotePort + ";branch=" + this.viaBranch;
+                    }
+                    viaArray.append(String.valueOf(viaH) + SIPStack.SIP_LINE_END);
+                    continue;
+                }
+                viaArray.append(String.valueOf(token) + SIPStack.SIP_LINE_END);
+                continue;
+            }
+            if (token.startsWith("v: ")) {
+                if (viaH == null) {
+                    viaH = token;
+                    if (token.indexOf(";received=") < 0) {
+                        String branch = "";
+                        int index = token.indexOf(";branch=");
+                        if (index > 0)
+                            branch = token.substring(index + 8);
+                        if (branch != null && branch.length() > 0) {
+                            index = branch.indexOf(";");
+                            if (index > 0) {
+                                this.viaBranch = branch.substring(0, index);
+                            } else {
+                                this.viaBranch = branch;
+                            }
+                        } else {
+                            this.viaBranch = branch;
+                        }
+                        index = token.indexOf(";branch=");
+                        if (index > 0) {
+                            viaH = token.substring(0, index);
+                        } else {
+                            viaH = token;
+                        }
+                        index = viaH.indexOf(";rport=");
+                        if (index > 0)
+                            viaH = viaH.substring(0, index);
+                        viaH = String.valueOf(viaH) + ";received=" + this.remoteIp + ";rport=" + this.remotePort + ";branch=" + this.viaBranch;
+                    }
+                    viaArray.append(String.valueOf(viaH) + SIPStack.SIP_LINE_END);
+                    continue;
+                }
+                viaArray.append(String.valueOf(token) + SIPStack.SIP_LINE_END);
+            }
+        }
+        return viaArray.toString();
+    }
+
+    public boolean constructSdp() {
+        if (this.sdp != null && this.sdp.flag)
+            return false;
+        if (SIPStack.localSdpIp != null && SIPStack.localSdpIp.length() > 0 && SIPStack.usePrivateWiMax) {
+            this.sdp = new SIPSdp(this.dnis, this.localIp, SIPStack.localSdpIp);
+        } else {
+            this.sdp = new SIPSdp(this.dnis, this.localIp);
+        }
+        if (this.sdp != null && this.sdp.flag)
+            return true;
+        return false;
+    }
+
+    public boolean parseRemoteSdp(String message) {
+        if (message == null || message.length() == 0)
+            return false;
+        boolean bContinueParsing = true;
+        int iS = 0;
+        int iE = 0;
+        String header = null;
+        if (bContinueParsing) {
+            bContinueParsing = false;
+            iS = message.indexOf(String.valueOf(SIPStack.SIP_LINE_END) + "Content-Type: ");
+            if (iS > 0) {
+                iE = message.indexOf(SIPStack.SIP_LINE_END, iS + 2);
+                if (iS > 0 && iE > 0) {
+                    header = message.substring(iS + 2, iE);
+                    String headerValue = null;
+                    if (header != null && header.length() > 0)
+                        headerValue = header.substring(14);
+                    if (headerValue != null && headerValue.length() > 0 && headerValue.toLowerCase().compareTo("application/sdp") == 0)
+                        bContinueParsing = true;
+                }
+            } else {
+                iS = message.indexOf(String.valueOf(SIPStack.SIP_LINE_END) + "c: ");
+                if (iS > 0) {
+                    iE = message.indexOf(SIPStack.SIP_LINE_END, iS + 2);
+                    if (iS > 0 && iE > 0) {
+                        header = message.substring(iS + 2, iE);
+                        String headerValue = null;
+                        if (header != null && header.length() > 0)
+                            headerValue = header.substring(3);
+                        if (headerValue != null && headerValue.length() > 0 && headerValue.toLowerCase().compareTo("application/sdp") == 0)
+                            bContinueParsing = true;
+                    }
+                }
+            }
+        }
+        iS = 0;
+        iE = 0;
+        header = null;
+        int contentLength = 0;
+        if (bContinueParsing) {
+            bContinueParsing = false;
+            iS = message.indexOf(String.valueOf(SIPStack.SIP_LINE_END) + "Content-Length: ");
+            if (iS > 0) {
+                iE = message.indexOf(SIPStack.SIP_LINE_END, iS + 2);
+                if (iS > 0 && iE > 0) {
+                    header = message.substring(iS + 2, iE);
+                    String headerValue = null;
+                    if (header != null && header.length() > 0)
+                        headerValue = header.substring(16);
+                    if (headerValue != null && headerValue.length() > 0) {
+                        contentLength = Integer.parseInt(headerValue);
+                        bContinueParsing = true;
+                    }
+                }
+            } else {
+                iS = message.indexOf(String.valueOf(SIPStack.SIP_LINE_END) + "l: ");
+                if (iS > 0) {
+                    iE = message.indexOf(SIPStack.SIP_LINE_END, iS + 2);
+                    if (iS > 0 && iE > 0) {
+                        header = message.substring(iS + 2, iE);
+                        String headerValue = null;
+                        if (header != null && header.length() > 0)
+                            headerValue = header.substring(3);
+                        if (headerValue != null && headerValue.length() > 0) {
+                            contentLength = Integer.parseInt(headerValue);
+                            bContinueParsing = true;
+                        }
+                    }
+                }
+            }
+        }
+        iS = 0;
+        iE = 0;
+        header = null;
+        String body = null;
+        if (bContinueParsing) {
+            bContinueParsing = false;
+            iS = message.indexOf(String.valueOf(SIPStack.SIP_LINE_DOUBLEEND) + "v=0" + SIPStack.SIP_LINE_END);
+            if (iS > 0) {
+                body = message.substring(iS + 4);
+                if (body != null && body.length() >= contentLength)
+                    bContinueParsing = true;
+            }
+        }
+        if (bContinueParsing) {
+            this.remoteSdp = new SIPSdp(body);
+            if (this.remoteSdp != null && this.remoteSdp.flag)
+                return true;
+        }
+        return false;
+    }
+
+    public boolean parseDtmfSdp(String message, int dtmftype) {
+        if (message == null || message.length() == 0)
+            return false;
+        boolean bContinueParsing = true;
+        int iS = 0;
+        int iE = 0;
+        int dtmf = 0;
+        this.bDtmfdetected = false;
+        String header = null;
+        if (dtmftype == SIPStack.SIP_DTMFINFO_DTMFRELAY) {
+            if (bContinueParsing) {
+                bContinueParsing = false;
+                iS = message.indexOf(String.valueOf(SIPStack.SIP_LINE_END) + "Content-Type: ");
+                if (iS > 0) {
+                    iE = message.indexOf(SIPStack.SIP_LINE_END, iS + 2);
+                    if (iS > 0 && iE > 0) {
+                        header = message.substring(iS + 2, iE);
+                        String headerValue = null;
+                        if (header != null && header.length() > 0)
+                            headerValue = header.substring(14);
+                        if (headerValue != null && headerValue.length() > 0 && headerValue.toLowerCase().compareTo("application/dtmf-relay") == 0)
+                            bContinueParsing = true;
+                    }
+                } else {
+                    iS = message.indexOf(String.valueOf(SIPStack.SIP_LINE_END) + "c: ");
+                    if (iS > 0) {
+                        iE = message.indexOf(SIPStack.SIP_LINE_END, iS + 2);
+                        if (iS > 0 && iE > 0) {
+                            header = message.substring(iS + 2, iE);
+                            String headerValue = null;
+                            if (header != null && header.length() > 0)
+                                headerValue = header.substring(3);
+                            if (headerValue != null && headerValue.length() > 0 && headerValue.toLowerCase().compareTo("application/dtmf-relay") == 0)
+                                bContinueParsing = true;
+                        }
+                    }
+                }
+            }
+            iS = 0;
+            iE = 0;
+            header = null;
+            int contentLength = 0;
+            if (bContinueParsing) {
+                bContinueParsing = false;
+                iS = message.indexOf(String.valueOf(SIPStack.SIP_LINE_END) + "Content-Length: ");
+                if (iS > 0) {
+                    iE = message.indexOf(SIPStack.SIP_LINE_END, iS + 2);
+                    if (iS > 0 && iE > 0) {
+                        header = message.substring(iS + 2, iE);
+                        String headerValue = null;
+                        if (header != null && header.length() > 0)
+                            headerValue = header.substring(16);
+                        if (headerValue != null && headerValue.length() > 0) {
+                            contentLength = Integer.parseInt(headerValue);
+                            bContinueParsing = true;
+                        }
+                    }
+                } else {
+                    iS = message.indexOf(String.valueOf(SIPStack.SIP_LINE_END) + "l: ");
+                    if (iS > 0) {
+                        iE = message.indexOf(SIPStack.SIP_LINE_END, iS + 2);
+                        if (iS > 0 && iE > 0) {
+                            header = message.substring(iS + 2, iE);
+                            String headerValue = null;
+                            if (header != null && header.length() > 0)
+                                headerValue = header.substring(3);
+                            if (headerValue != null && headerValue.length() > 0) {
+                                contentLength = Integer.parseInt(headerValue);
+                                bContinueParsing = true;
+                            }
+                        }
+                    }
+                }
+            }
+            iS = 0;
+            iE = 0;
+            header = null;
+            String body = null;
+            if (bContinueParsing) {
+                bContinueParsing = false;
+                iS = message.indexOf(String.valueOf(SIPStack.SIP_LINE_DOUBLEEND) + "Signal=");
+                if (iS > 0) {
+                    body = message.substring(iS + 4);
+                    if (body != null && body.length() >= contentLength)
+                        bContinueParsing = true;
+                }
+            }
+            if (bContinueParsing) {
+                bContinueParsing = false;
+                String sH = null;
+                iS = body.indexOf("Signal=");
+                if (iS >= 0)
+                    iE = body.indexOf(SIPStack.SIP_LINE_END, iS);
+                if (iS >= 0 && iE > iS) {
+                    sH = body.substring(iS + 7, iE).trim();
+                    dtmf = Integer.parseInt(sH);
+                    if (dtmf >= 0 && dtmf < 12) {
+                        bContinueParsing = true;
+                        this.detectedDtmf = dtmf;
+                        this.bDtmfdetected = true;
+                        this.dtmfDuration = 0;
+                    }
+                }
+                if (bContinueParsing) {
+                    iS = body.indexOf("Duration=");
+                    if (iS >= 0)
+                        iE = body.indexOf(SIPStack.SIP_LINE_END, iS);
+                    if (iS >= 0 && iE > iS) {
+                        sH = body.substring(iS + 9, iE).trim();
+                        this.dtmfDuration = Integer.parseInt(sH);
+                    }
+                }
+            }
+            return this.bDtmfdetected;
+        }
+        if (dtmftype == SIPStack.SIP_DTMFINFO_DTMF) {
+            if (bContinueParsing) {
+                bContinueParsing = false;
+                iS = message.indexOf(String.valueOf(SIPStack.SIP_LINE_END) + "Content-Type: ");
+                if (iS > 0) {
+                    iE = message.indexOf(SIPStack.SIP_LINE_END, iS + 2);
+                    if (iS > 0 && iE > 0) {
+                        header = message.substring(iS + 2, iE);
+                        String headerValue = null;
+                        if (header != null && header.length() > 0)
+                            headerValue = header.substring(14);
+                        if (headerValue != null && headerValue.length() > 0 && headerValue.toLowerCase().compareTo("application/dtmf") == 0)
+                            bContinueParsing = true;
+                    }
+                } else {
+                    iS = message.indexOf(String.valueOf(SIPStack.SIP_LINE_END) + "c: ");
+                    if (iS > 0) {
+                        iE = message.indexOf(SIPStack.SIP_LINE_END, iS + 2);
+                        if (iS > 0 && iE > 0) {
+                            header = message.substring(iS + 2, iE);
+                            String headerValue = null;
+                            if (header != null && header.length() > 0)
+                                headerValue = header.substring(3);
+                            if (headerValue != null && headerValue.length() > 0 && headerValue.toLowerCase().compareTo("application/dtmf") == 0)
+                                bContinueParsing = true;
+                        }
+                    }
+                }
+            }
+            iS = 0;
+            iE = 0;
+            header = null;
+            int contentLength = 0;
+            if (bContinueParsing) {
+                bContinueParsing = false;
+                iS = message.indexOf(String.valueOf(SIPStack.SIP_LINE_END) + "Content-Length: ");
+                if (iS > 0) {
+                    iE = message.indexOf(SIPStack.SIP_LINE_END, iS + 2);
+                    if (iS > 0 && iE > 0) {
+                        header = message.substring(iS + 2, iE);
+                        String headerValue = null;
+                        if (header != null && header.length() > 0)
+                            headerValue = header.substring(16);
+                        if (headerValue != null && headerValue.length() > 0) {
+                            contentLength = Integer.parseInt(headerValue);
+                            bContinueParsing = true;
+                        }
+                    }
+                } else {
+                    iS = message.indexOf(String.valueOf(SIPStack.SIP_LINE_END) + "l: ");
+                    if (iS > 0) {
+                        iE = message.indexOf(SIPStack.SIP_LINE_END, iS + 2);
+                        if (iS > 0 && iE > 0) {
+                            header = message.substring(iS + 2, iE);
+                            String headerValue = null;
+                            if (header != null && header.length() > 0)
+                                headerValue = header.substring(3);
+                            if (headerValue != null && headerValue.length() > 0) {
+                                contentLength = Integer.parseInt(headerValue);
+                                bContinueParsing = true;
+                            }
+                        }
+                    }
+                }
+            }
+            iS = 0;
+            iE = 0;
+            header = null;
+            String body = null;
+            if (bContinueParsing) {
+                bContinueParsing = false;
+                iS = message.indexOf(SIPStack.SIP_LINE_DOUBLEEND);
+                if (iS > 0) {
+                    body = message.substring(iS + 4);
+                    if (body != null && body.length() >= contentLength)
+                        bContinueParsing = true;
+                }
+            }
+            if (bContinueParsing) {
+                bContinueParsing = false;
+                String sH = null;
+                iS = 0;
+                iE = body.indexOf(SIPStack.SIP_LINE_END, iS);
+                if (iE > iS) {
+                    sH = body.substring(iS, iE).trim();
+                    dtmf = Integer.parseInt(sH);
+                    if (dtmf >= 0 && dtmf < 12) {
+                        bContinueParsing = true;
+                        this.detectedDtmf = dtmf;
+                        this.bDtmfdetected = true;
+                        this.dtmfDuration = 0;
+                    }
+                }
+            }
+            return this.bDtmfdetected;
+        }
+        return false;
+    }
+
+    public boolean negotiateAudioCodec() {
+        if (this.sdp != null && this.sdp.flag && this.sdp.audioM != null && this.sdp.audioM.flag &&
+                this.remoteSdp != null && this.remoteSdp.flag && this.remoteSdp.audioM != null &&
+                this.remoteSdp.audioM.flag)
+            if (this.callDirection == SIPStack.SIP_CALLDIRECTION_OUT) {
+                int finalCodec = this.remoteSdp.audioM.negotiateAudioCodec(this.sdp.audioM.codecS.toString());
+                if (finalCodec >= 0) {
+                    this.sdp.audioM.setCommonCodec(finalCodec);
+                    return true;
+                }
+            } else if (this.callDirection == SIPStack.SIP_CALLDIRECTION_IN) {
+                int finalCodec = this.sdp.audioM.negotiateAudioCodec(this.remoteSdp.audioM.codecS.toString());
+                if (finalCodec >= 0) {
+                    this.remoteSdp.audioM.setCommonCodec(finalCodec);
+                    return true;
+                }
+            }
+        return false;
+    }
+
+    public boolean negotiateVideoCodec() {
+        return true;
+    }
+
+    public void exceptionTI() {
+        if (SIPStack.SIP_CALLHANDLE_DEBUG)
+            System.out.println("IDLE CALL EXCEPTION occurred.");
+        resetCall();
+    }
+
+    public void exceptionT0() {
+        if (SIPStack.SIP_CALLHANDLE_DEBUG)
+            System.out.println("INVITING CALL EXCEPTION occurred.");
+        resetCall();
+    }
+
+    public void exceptionT1() {
+        if (SIPStack.SIP_CALLHANDLE_DEBUG)
+            System.out.println("PROCEEDING CALL EXCEPTION occurred.");
+    }
+
+    public void exceptionT2() {
+        if (SIPStack.SIP_CALLHANDLE_DEBUG)
+            System.out.println("PROGRESSING CALL EXCEPTION occurred.");
+    }
+
+    public void exceptionT3() {
+        if (SIPStack.SIP_CALLHANDLE_DEBUG)
+            System.out.println("ACCEPTED CALL EXCEPTION occurred.");
+    }
+
+    public void exceptionT4() {
+        if (SIPStack.SIP_CALLHANDLE_DEBUG)
+            System.out.println("CONNECTED CALL EXCEPTION occurred.");
+    }
+
+    public void exceptionT5() {
+        if (SIPStack.SIP_CALLHANDLE_DEBUG)
+            System.out.println("DISCONNECTING CALL EXCEPTION occurred.");
+        resetCall();
+    }
+
+    public void exceptionT6() {
+        if (SIPStack.SIP_CALLHANDLE_DEBUG)
+            System.out.println("TERMINATING CALL EXCEPTION occurred.");
+        resetCall();
+    }
+
+    public void exceptionT7() {
+        if (SIPStack.SIP_CALLHANDLE_DEBUG)
+            System.out.println("OFFERRED CALL EXCEPTION occurred.");
+    }
+
+    public void exceptionT8() {
+        if (SIPStack.SIP_CALLHANDLE_DEBUG)
+            System.out.println("CANCELLING CALL EXCEPTION occurred.");
+        resetCall();
+    }
+
+    public void setUpdateheaders() {
+        if (this.updateHeaders == null)
+            return;
+        this.updateHeaders.commandLine = this.commandLine;
+        this.updateHeaders.viaH = this.viaH;
+        this.updateHeaders.viaArray = this.viaArray;
+        this.updateHeaders.routeH = this.routeH;
+        this.updateHeaders.routeArray = this.routeArray;
+        this.updateHeaders.recordrouteH = this.recordrouteH;
+        this.updateHeaders.recordrouteArray = this.recordrouteArray;
+        this.updateHeaders.maxforwardH = this.maxforwardH;
+        this.updateHeaders.contactH = this.contactH;
+        this.updateHeaders.toH = this.toH;
+        this.updateHeaders.fromH = this.fromH;
+        this.updateHeaders.callidH = this.callidH;
+        this.updateHeaders.cseqH = this.cseqH;
+        this.updateHeaders.expiresH = this.expiresH;
+        this.updateHeaders.allowH = this.allowH;
+        this.updateHeaders.useragentH = this.useragentH;
+        this.updateHeaders.remoteuseragentH = this.remoteuseragentH;
+        this.updateHeaders.contentlengthH = this.contentlengthH;
+        this.updateHeaders.contenttypeH = this.contenttypeH;
+        this.updateHeaders.authorizationINVITEH = this.authorizationINVITEH;
+        this.updateHeaders.authorizationCANCELH = this.authorizationCANCELH;
+        this.updateHeaders.authorizationBYEH = this.authorizationBYEH;
+        this.updateHeaders.authorizationACKH = this.authorizationACKH;
+        this.updateHeaders.passertedidentityH = this.passertedidentityH;
+        this.updateHeaders.serverIp = this.serverIp;
+        this.updateHeaders.serverPort = this.serverPort;
+        this.updateHeaders.serverDomain = this.serverDomain;
+        this.updateHeaders.remoteIp = this.remoteIp;
+        this.updateHeaders.remotePort = this.remotePort;
+        this.updateHeaders.remoteContactIp = this.remoteContactIp;
+        this.updateHeaders.remoteContactPort = this.remoteContactPort;
+        this.updateHeaders.remoteContactUri = this.remoteContactUri;
+        this.updateHeaders.localIp = this.localIp;
+        this.updateHeaders.localPort = this.localPort;
+        this.updateHeaders.id = this.id;
+        this.updateHeaders.cid = this.cid;
+        this.updateHeaders.authid = this.authid;
+        this.updateHeaders.authpassword = this.authpassword;
+        this.updateHeaders.fromTag = this.fromTag;
+        this.updateHeaders.toTag = this.toTag;
+        this.updateHeaders.fromHeaderValue = this.fromHeaderValue;
+        this.updateHeaders.toHeaderValue = this.toHeaderValue;
+        this.updateHeaders.callId = this.callId;
+        this.updateHeaders.dnis = this.dnis;
+        this.updateHeaders.CSEQ_NUMBER = this.CSEQ_NUMBER;
+        this.updateHeaders.INVITE_CSEQ = this.INVITE_CSEQ;
+        this.updateHeaders.CANCEL_CSEQ = this.CANCEL_CSEQ;
+        this.updateHeaders.ACK_CSEQ = this.ACK_CSEQ;
+        this.updateHeaders.BYE_CSEQ = this.BYE_CSEQ;
+        this.updateHeaders.callDirection = this.callDirection;
+        this.updateHeaders.viaBranch = this.viaBranch;
+        this.updateHeaders.callState = this.callState;
+        this.updateHeaders.callMode = this.callMode;
+        this.updateHeaders.callTime_TI = this.callTime_TI;
+        this.updateHeaders.callTime_T0 = this.callTime_T0;
+        this.updateHeaders.callTime_T00 = this.callTime_T00;
+        this.updateHeaders.invitingTimes = this.invitingTimes;
+        this.updateHeaders.callTime_T1 = this.callTime_T1;
+        this.updateHeaders.callTime_T2 = this.callTime_T2;
+        this.updateHeaders.callTime_T3 = this.callTime_T3;
+        this.updateHeaders.callTime_T4 = this.callTime_T4;
+        this.updateHeaders.callTime_T40 = this.callTime_T40;
+        this.updateHeaders.callTime_T5 = this.callTime_T5;
+        this.updateHeaders.callTime_T6 = this.callTime_T6;
+        this.updateHeaders.callTime_T7 = this.callTime_T7;
+        this.updateHeaders.callTime_T8 = this.callTime_T8;
+        this.updateHeaders.callTime_T9 = this.callTime_T9;
+        this.updateHeaders.expiresTI = this.expiresTI;
+        this.updateHeaders.expiresT0 = this.expiresT0;
+        this.updateHeaders.expiresT1 = this.expiresT1;
+        this.updateHeaders.expiresT2 = this.expiresT2;
+        this.updateHeaders.expiresT3 = this.expiresT3;
+        this.updateHeaders.expiresT4 = this.expiresT4;
+        this.updateHeaders.expiresT5 = this.expiresT5;
+        this.updateHeaders.expiresT6 = this.expiresT6;
+        this.updateHeaders.expiresT7 = this.expiresT7;
+        this.updateHeaders.expiresT8 = this.expiresT8;
+        this.updateHeaders.expiresT9 = this.expiresT9;
+        this.updateHeaders.sdp = this.sdp;
+        this.updateHeaders.remoteSdp = this.remoteSdp;
+        this.updateHeaders.message = this.message;
+        this.commandLine = null;
+        this.viaH = null;
+        this.viaArray = null;
+        this.routeH = null;
+        this.routeArray = null;
+        this.recordrouteH = null;
+        this.recordrouteArray = null;
+        this.maxforwardH = null;
+        this.contactH = null;
+        this.toH = null;
+        this.fromH = null;
+        this.callidH = null;
+        this.cseqH = null;
+        this.expiresH = null;
+        this.allowH = null;
+        this.useragentH = null;
+        this.remoteuseragentH = null;
+        this.contentlengthH = null;
+        this.contenttypeH = null;
+        this.authorizationINVITEH = null;
+        this.authorizationCANCELH = null;
+        this.authorizationBYEH = null;
+        this.authorizationACKH = null;
+        this.passertedidentityH = null;
+        this.fromTag = null;
+        this.toTag = null;
+        this.callId = null;
+        this.viaBranch = null;
+        this.sdp = null;
+        this.remoteSdp = null;
+        this.message = null;
+        this.updateHeaders.flag = true;
+    }
+
+    public void setUpdateheaders(String flow) {
+        if (this.updateHeaders == null)
+            return;
+        this.updateHeaders.commandLine = this.commandLine;
+        this.updateHeaders.viaH = this.viaH;
+        this.updateHeaders.viaArray = this.viaArray;
+        this.updateHeaders.routeH = this.routeH;
+        this.updateHeaders.routeArray = this.routeArray;
+        this.updateHeaders.recordrouteH = this.recordrouteH;
+        this.updateHeaders.recordrouteArray = this.recordrouteArray;
+        this.updateHeaders.maxforwardH = this.maxforwardH;
+        this.updateHeaders.contactH = this.contactH;
+        this.updateHeaders.toH = this.toH;
+        this.updateHeaders.fromH = this.fromH;
+        this.updateHeaders.callidH = this.callidH;
+        this.updateHeaders.cseqH = this.cseqH;
+        this.updateHeaders.expiresH = this.expiresH;
+        this.updateHeaders.allowH = this.allowH;
+        this.updateHeaders.useragentH = this.useragentH;
+        this.updateHeaders.remoteuseragentH = this.remoteuseragentH;
+        this.updateHeaders.contentlengthH = this.contentlengthH;
+        this.updateHeaders.contenttypeH = this.contenttypeH;
+        this.updateHeaders.authorizationINVITEH = this.authorizationINVITEH;
+        this.updateHeaders.authorizationCANCELH = this.authorizationCANCELH;
+        this.updateHeaders.authorizationBYEH = this.authorizationBYEH;
+        this.updateHeaders.authorizationACKH = this.authorizationACKH;
+        this.updateHeaders.passertedidentityH = this.passertedidentityH;
+        this.updateHeaders.serverIp = this.serverIp;
+        this.updateHeaders.serverPort = this.serverPort;
+        this.updateHeaders.serverDomain = this.serverDomain;
+        this.updateHeaders.remoteIp = this.remoteIp;
+        this.updateHeaders.remotePort = this.remotePort;
+        this.updateHeaders.remoteContactIp = this.remoteContactIp;
+        this.updateHeaders.remoteContactPort = this.remoteContactPort;
+        this.updateHeaders.remoteContactUri = this.remoteContactUri;
+        this.updateHeaders.localIp = this.localIp;
+        this.updateHeaders.localPort = this.localPort;
+        this.updateHeaders.id = this.id;
+        this.updateHeaders.cid = this.cid;
+        this.updateHeaders.authid = this.authid;
+        this.updateHeaders.authpassword = this.authpassword;
+        this.updateHeaders.fromTag = this.fromTag;
+        this.updateHeaders.toTag = this.toTag;
+        this.updateHeaders.fromHeaderValue = this.fromHeaderValue;
+        this.updateHeaders.toHeaderValue = this.toHeaderValue;
+        this.updateHeaders.callId = this.callId;
+        this.updateHeaders.dnis = this.dnis;
+        this.updateHeaders.CSEQ_NUMBER = this.CSEQ_NUMBER;
+        this.updateHeaders.INVITE_CSEQ = this.INVITE_CSEQ;
+        this.updateHeaders.CANCEL_CSEQ = this.CANCEL_CSEQ;
+        this.updateHeaders.ACK_CSEQ = this.ACK_CSEQ;
+        this.updateHeaders.BYE_CSEQ = this.BYE_CSEQ;
+        this.updateHeaders.callDirection = this.callDirection;
+        this.updateHeaders.viaBranch = this.viaBranch;
+        this.updateHeaders.callState = this.callState;
+        this.updateHeaders.callMode = this.callMode;
+        this.updateHeaders.callTime_TI = this.callTime_TI;
+        this.updateHeaders.callTime_T0 = this.callTime_T0;
+        this.updateHeaders.callTime_T00 = this.callTime_T00;
+        this.updateHeaders.invitingTimes = this.invitingTimes;
+        this.updateHeaders.callTime_T1 = this.callTime_T1;
+        this.updateHeaders.callTime_T2 = this.callTime_T2;
+        this.updateHeaders.callTime_T3 = this.callTime_T3;
+        this.updateHeaders.callTime_T4 = this.callTime_T4;
+        this.updateHeaders.callTime_T40 = this.callTime_T40;
+        this.updateHeaders.callTime_T5 = this.callTime_T5;
+        this.updateHeaders.callTime_T6 = this.callTime_T6;
+        this.updateHeaders.callTime_T7 = this.callTime_T7;
+        this.updateHeaders.callTime_T8 = this.callTime_T8;
+        this.updateHeaders.callTime_T9 = this.callTime_T9;
+        this.updateHeaders.expiresTI = this.expiresTI;
+        this.updateHeaders.expiresT0 = this.expiresT0;
+        this.updateHeaders.expiresT1 = this.expiresT1;
+        this.updateHeaders.expiresT2 = this.expiresT2;
+        this.updateHeaders.expiresT3 = this.expiresT3;
+        this.updateHeaders.expiresT4 = this.expiresT4;
+        this.updateHeaders.expiresT5 = this.expiresT5;
+        this.updateHeaders.expiresT6 = this.expiresT6;
+        this.updateHeaders.expiresT7 = this.expiresT7;
+        this.updateHeaders.expiresT8 = this.expiresT8;
+        this.updateHeaders.expiresT9 = this.expiresT9;
+        this.updateHeaders.sdp = this.sdp;
+        this.updateHeaders.remoteSdp = this.remoteSdp;
+        this.updateHeaders.message = this.message;
+        this.commandLine = null;
+        this.viaH = null;
+        this.viaArray = null;
+        this.recordrouteH = null;
+        this.recordrouteArray = null;
+        this.maxforwardH = null;
+        this.contactH = null;
+        if (this.updateHeaders.callDirection == SIPStack.SIP_CALLDIRECTION_IN) {
+            if (this.updateHeaders.fromH != null && this.updateHeaders.fromH.length() > 5)
+                if (this.updateHeaders.fromH.startsWith("f: ")) {
+                    this.toH = "t:" + this.updateHeaders.fromH.substring(2);
+                } else {
+                    this.toH = "To:" + this.updateHeaders.fromH.substring(5);
+                }
+            if (this.updateHeaders.toH != null && this.updateHeaders.toH.length() > 3)
+                if (this.updateHeaders.toH.startsWith("t: ")) {
+                    this.fromH = "From:" + this.updateHeaders.toH.substring(2);
+                } else {
+                    this.fromH = "From:" + this.updateHeaders.toH.substring(3);
+                }
+            this.fromTag = this.updateHeaders.toTag;
+            this.toTag = this.updateHeaders.fromTag;
+        }
+        this.cseqH = null;
+        this.expiresH = null;
+        this.allowH = null;
+        this.useragentH = null;
+        this.remoteuseragentH = null;
+        this.contentlengthH = null;
+        this.contenttypeH = null;
+        this.viaBranch = null;
+        if (this.updateHeaders.callDirection == SIPStack.SIP_CALLDIRECTION_IN) {
+            this.authorizationINVITEH = null;
+            this.authorizationCANCELH = null;
+            this.authorizationBYEH = null;
+            this.authorizationACKH = null;
+        }
+        this.passertedidentityH = null;
+        this.callState = 20;
+        this.callMode = SIPStack.SIP_CALLMODE_HOLD;
+        this.callTime_TI = new Date();
+        this.callTime_T0 = new Date();
+        this.callTime_T00 = new Date();
+        this.invitingTimes = 0;
+        this.callTime_T1 = new Date();
+        this.callTime_T2 = new Date();
+        this.callTime_T3 = new Date();
+        this.callTime_T4 = new Date();
+        this.callTime_T40 = new Date();
+        this.callTime_T5 = new Date();
+        this.callTime_T6 = new Date();
+        this.callTime_T7 = new Date();
+        this.callTime_T8 = new Date();
+        this.callTime_T9 = new Date();
+        this.expiresTI = 0;
+        this.expiresT0 = 0;
+        this.expiresT1 = 0;
+        this.expiresT2 = 0;
+        this.expiresT3 = 0;
+        this.expiresT4 = 0;
+        this.expiresT5 = 0;
+        this.expiresT6 = 0;
+        this.expiresT7 = 0;
+        this.expiresT8 = 0;
+        this.expiresT9 = 0;
+        this.sdp = null;
+        this.remoteSdp = null;
+        int audioport = this.updateHeaders.sdp.audioM.mediaPort;
+        if (audioport > 0)
+            constructSdp();
+        if (this.sdp != null && this.sdp.flag) {
+            this.sdp.setMediaPort(SIPStack.SIP_MEDIATYPE_AUDIO, audioport);
+            if (this.sdp.audioM != null) {
+                if (this.updateHeaders.sdp.audioM.commonCodec == SIPStack.SIP_CODEC_G711U) {
+                    this.sdp.setCodec(
+                            SIPStack.SIP_MEDIATYPE_AUDIO,
+                            SIPStack.SIP_CODEC_G711U,
+                            "PCMU/8000");
+                } else if (this.updateHeaders.sdp.audioM.commonCodec == SIPStack.SIP_CODEC_G711A) {
+                    this.sdp.setCodec(
+                            SIPStack.SIP_MEDIATYPE_AUDIO,
+                            SIPStack.SIP_CODEC_G711A,
+                            "PCMA/8000");
+                }
+                this.sdp.setCodec(
+                        SIPStack.SIP_MEDIATYPE_AUDIO,
+                        RFC2833.payloadType,
+                        "telephone-event/8000");
+                this.sdp.setFmtpDescribe(SIPStack.SIP_MEDIATYPE_AUDIO, RFC2833.payloadType, "0-15");
+                this.sdp.audioM.setFlow(flow);
+            }
+        }
+        this.message = null;
+        this.updateHeaders.flag = true;
+    }
+
+    public void restoreUpdateheaders() {
+        if (this.updateHeaders == null || !this.updateHeaders.flag)
+            return;
+        this.commandLine = this.updateHeaders.commandLine;
+        this.viaH = this.updateHeaders.viaH;
+        this.viaArray = this.updateHeaders.viaArray;
+        this.routeH = this.updateHeaders.routeH;
+        this.routeArray = this.updateHeaders.routeArray;
+        this.recordrouteH = this.updateHeaders.recordrouteH;
+        this.recordrouteArray = this.updateHeaders.recordrouteArray;
+        this.maxforwardH = this.updateHeaders.maxforwardH;
+        this.contactH = this.updateHeaders.contactH;
+        this.toH = this.updateHeaders.toH;
+        this.fromH = this.updateHeaders.fromH;
+        this.callidH = this.updateHeaders.callidH;
+        this.cseqH = this.updateHeaders.cseqH;
+        this.expiresH = this.updateHeaders.expiresH;
+        this.allowH = this.updateHeaders.allowH;
+        this.useragentH = this.updateHeaders.useragentH;
+        this.remoteuseragentH = this.updateHeaders.remoteuseragentH;
+        this.contentlengthH = this.updateHeaders.contentlengthH;
+        this.contenttypeH = this.updateHeaders.contenttypeH;
+        this.authorizationINVITEH = this.updateHeaders.authorizationINVITEH;
+        this.authorizationCANCELH = this.updateHeaders.authorizationCANCELH;
+        this.authorizationBYEH = this.updateHeaders.authorizationBYEH;
+        this.authorizationACKH = this.updateHeaders.authorizationACKH;
+        this.passertedidentityH = this.updateHeaders.passertedidentityH;
+        this.serverIp = this.updateHeaders.serverIp;
+        this.serverPort = this.updateHeaders.serverPort;
+        this.serverDomain = this.updateHeaders.serverDomain;
+        this.remoteIp = this.updateHeaders.remoteIp;
+        this.remotePort = this.updateHeaders.remotePort;
+        this.remoteContactIp = this.updateHeaders.remoteContactIp;
+        this.remoteContactPort = this.updateHeaders.remoteContactPort;
+        this.remoteContactUri = this.updateHeaders.remoteContactUri;
+        this.localIp = this.updateHeaders.localIp;
+        this.localPort = this.updateHeaders.localPort;
+        this.id = this.updateHeaders.id;
+        this.cid = this.updateHeaders.cid;
+        this.authid = this.updateHeaders.authid;
+        this.authpassword = this.updateHeaders.authpassword;
+        this.fromTag = this.updateHeaders.fromTag;
+        this.toTag = this.updateHeaders.toTag;
+        this.fromHeaderValue = this.updateHeaders.fromHeaderValue;
+        this.toHeaderValue = this.updateHeaders.toHeaderValue;
+        this.callId = this.updateHeaders.callId;
+        this.dnis = this.updateHeaders.dnis;
+        this.CSEQ_NUMBER = this.updateHeaders.CSEQ_NUMBER;
+        this.INVITE_CSEQ = this.updateHeaders.INVITE_CSEQ;
+        this.CANCEL_CSEQ = this.updateHeaders.CANCEL_CSEQ;
+        this.ACK_CSEQ = this.updateHeaders.ACK_CSEQ;
+        this.BYE_CSEQ = this.updateHeaders.BYE_CSEQ;
+        this.callDirection = this.updateHeaders.callDirection;
+        this.viaBranch = this.updateHeaders.viaBranch;
+        this.callState = this.updateHeaders.callState;
+        this.callMode = this.updateHeaders.callMode;
+        this.callTime_TI = this.updateHeaders.callTime_TI;
+        this.callTime_T0 = this.updateHeaders.callTime_T0;
+        this.callTime_T00 = this.updateHeaders.callTime_T00;
+        this.invitingTimes = this.updateHeaders.invitingTimes;
+        this.callTime_T1 = this.updateHeaders.callTime_T1;
+        this.callTime_T2 = this.updateHeaders.callTime_T2;
+        this.callTime_T3 = this.updateHeaders.callTime_T3;
+        this.callTime_T4 = this.updateHeaders.callTime_T4;
+        this.callTime_T40 = this.updateHeaders.callTime_T40;
+        this.callTime_T5 = this.updateHeaders.callTime_T5;
+        this.callTime_T6 = this.updateHeaders.callTime_T6;
+        this.callTime_T7 = this.updateHeaders.callTime_T7;
+        this.callTime_T8 = this.updateHeaders.callTime_T8;
+        this.callTime_T9 = this.updateHeaders.callTime_T9;
+        this.expiresTI = this.updateHeaders.expiresTI;
+        this.expiresT0 = this.updateHeaders.expiresT0;
+        this.expiresT1 = this.updateHeaders.expiresT1;
+        this.expiresT2 = this.updateHeaders.expiresT2;
+        this.expiresT3 = this.updateHeaders.expiresT3;
+        this.expiresT4 = this.updateHeaders.expiresT4;
+        this.expiresT5 = this.updateHeaders.expiresT5;
+        this.expiresT6 = this.updateHeaders.expiresT6;
+        this.expiresT7 = this.updateHeaders.expiresT7;
+        this.expiresT8 = this.updateHeaders.expiresT8;
+        this.expiresT9 = this.updateHeaders.expiresT9;
+        this.sdp = this.updateHeaders.sdp;
+        this.remoteSdp = this.updateHeaders.remoteSdp;
+        this.message = this.updateHeaders.message;
+        this.updateHeaders.flag = false;
+    }
+
+    public void resetUpdateheaders() {
+        if (this.updateHeaders == null || !this.updateHeaders.flag)
+            return;
+        this.updateHeaders.reset();
+    }
+
+    public boolean isCurrentCall(String message) {
+        try {
+            SIPHeader sipHeader = new SIPHeader(message, SIPStack.SIP_HEADERTYPE_CALLID);
+            if (sipHeader != null && sipHeader.flag)
+                if (sipHeader.headerValue != null &&
+                        sipHeader.headerValue.length() > 0 &&
+                        this.callId != null &&
+                        sipHeader.headerValue.compareTo(this.callId) == 0)
+                    return true;
+        } catch (Exception exception) {}
+        return false;
+    }
+
+    public String getCallState() {
+        switch (this.callState) {
+            case 0:
+                return "Idle";
+            case 1:
+                return "Inviting";
+            case 2:
+                return "Offerred";
+            case 3:
+                return "Proceeding";
+            case 4:
+                return "Progressing";
+            case 5:
+                return "Accepted";
+            case 6:
+                return "Remoteaccepted";
+            case 7:
+                return "Connected";
+            case 8:
+                return "Disconnecting";
+            case 9:
+                return "Terminating";
+            case 10:
+                return "Unauthorized";
+            case 11:
+                return "Cancelling";
+            case 13:
+                return "Recancelling";
+            case 14:
+                return "Cancelremoteaccepted";
+            case 12:
+                return "Cancelled";
+            case 15:
+                return "Rejected";
+            case 16:
+                return "Redirected";
+            case 20:
+                return "Updating";
+            case 21:
+                return "Updateproceeding";
+            case 22:
+                return "Updateprogressing";
+            case 23:
+                return "Updateofferred";
+            case 24:
+                return "Updateaccepted";
+            case 25:
+                return "Updaterejected";
+            case 26:
+                return "Updateremoteaccepted";
+            case 27:
+                return "Updateremoterejected";
+            case 28:
+                return "Updateunauthorized";
+            case 29:
+                return "Updateredirected";
+        }
+        return "Undefined";
+    }
+}

+ 362 - 0
WallPadCall/src/main/java/bssoft/stack/sip/SIPG711.java

@@ -0,0 +1,362 @@
+package bssoft.stack.sip;
+
+public class SIPG711 {
+    static final int SIGN_BIT = 128;
+
+    static final int QUANT_MASK = 15;
+
+    static final int NSEGS = 8;
+
+    static final int SEG_SHIFT = 4;
+
+    static final int SEG_MASK = 112;
+
+    static final int[] seg_end = new int[] { 255, 511, 1023, 2047, 4095, 8191, 16383, 32767 };
+
+    static final int[] _u2a = new int[] {
+            1, 1, 2, 2, 3, 3, 4, 4,
+
+            5, 5,
+            6, 6, 7, 7, 8, 8,
+
+            9, 10, 11, 12,
+            13, 14, 15, 16,
+
+            17, 18, 19, 20, 21, 22,
+            23, 24,
+
+            25, 27, 29, 31, 33, 34, 35, 36,
+            37, 38, 39, 40, 41, 42, 43, 44,
+
+            46, 48,
+            49, 50, 51, 52, 53, 54,
+
+            55, 56, 57, 58,
+            59, 60, 61, 62,
+
+            64, 65, 66, 67, 68, 69,
+            70, 71,
+
+            72, 73, 74, 75, 76, 77, 78, 79,
+            81, 82, 83, 84, 85, 86, 87, 88,
+
+            89, 90,
+            91, 92, 93, 94, 95, 96,
+
+            97, 98, 99, 100,
+            101, 102, 103, 104,
+
+            105, 106, 107, 108, 109, 110,
+            111, 112,
+
+            113, 114, 115, 116, 117, 118, 119, 120,
+            121, 122, 123, 124, 125, 126, 127, 128 };
+
+    static final int[] _a2u = new int[] {
+            1, 3, 5, 7, 9, 11, 13, 15,
+
+            16, 17,
+            18, 19, 20, 21, 22, 23,
+
+            24, 25, 26, 27,
+            28, 29, 30, 31,
+
+            32, 32, 33, 33, 34, 34,
+            35, 35,
+
+            36, 37, 38, 39, 40, 41, 42, 43,
+            44, 45, 46, 47, 48, 48, 49, 49,
+
+            50, 51,
+            52, 53, 54, 55, 56, 57,
+
+            58, 59, 60, 61,
+            62, 63, 64, 64,
+
+            65, 66, 67, 68, 69, 70,
+            71, 72,
+
+            73, 74, 75, 76, 77, 78, 79, 79,
+            80, 81, 82, 83, 84, 85, 86, 87,
+
+            88, 89,
+            90, 91, 92, 93, 94, 95,
+
+            96, 97, 98, 99,
+            100, 101, 102, 103,
+
+            104, 105, 106, 107, 108, 109,
+            110, 111,
+
+            112, 113, 114, 115, 116, 117, 118, 119,
+            120, 121, 122, 123, 124, 125, 126, 127 };
+
+    public static final int BIAS = 132;
+
+    static int search(int val, int[] table) {
+        for (int i = 0; i < table.length; ) {
+            if (val <= table[i])
+                return i;
+            i++;
+        }
+        return table.length;
+    }
+
+    public static int linear2alaw(int pcm_val) {
+        int mask;
+        if (pcm_val >= 0) {
+            mask = 213;
+        } else {
+            mask = 85;
+            pcm_val = -pcm_val - 8;
+        }
+        int seg = search(pcm_val, seg_end);
+        if (seg >= 8)
+            return 0x7F ^ mask;
+        int aval = seg << 4;
+        if (seg < 2) {
+            aval |= pcm_val >> 4 & 0xF;
+        } else {
+            aval |= pcm_val >> seg + 3 & 0xF;
+        }
+        return aval ^ mask;
+    }
+
+    public static int alaw2linear(int a_val) {
+        a_val ^= 0x55;
+        int t = (a_val & 0xF) << 4;
+        int seg = (a_val & 0x70) >> 4;
+        switch (seg) {
+            case 0:
+                t += 8;
+                break;
+            case 1:
+                t += 264;
+                break;
+            default:
+                t += 264;
+                t <<= seg - 1;
+                break;
+        }
+        return ((a_val & 0x80) != 0) ? t : -t;
+    }
+
+    public static int linear2ulaw(int pcm_val) {
+        int mask;
+        if (pcm_val < 0) {
+            pcm_val = 132 - pcm_val;
+            mask = 127;
+        } else {
+            pcm_val += 132;
+            mask = 255;
+        }
+        int seg = search(pcm_val, seg_end);
+        if (seg >= 8)
+            return 0x7F ^ mask;
+        int uval = seg << 4 | pcm_val >> seg + 3 & 0xF;
+        return uval ^ mask;
+    }
+
+    public static int ulaw2linear(int u_val) {
+        u_val ^= 0xFFFFFFFF;
+        int t = ((u_val & 0xF) << 3) + 132;
+        t <<= (u_val & 0x70) >> 4;
+        return ((u_val & 0x80) != 0) ? (132 - t) : (t - 132);
+    }
+
+    public static int alaw2ulaw(int aval) {
+        aval &= 0xFF;
+        return ((aval & 0x80) != 0) ? (0xFF ^ _a2u[aval ^ 0xD5]) : (0x7F ^ _a2u[aval ^ 0x55]);
+    }
+
+    public static int ulaw2alaw(int uval) {
+        uval &= 0xFF;
+        return ((uval & 0x80) != 0) ? (0xD5 ^ _u2a[0xFF ^ uval] - 1) : (0x55 ^ _u2a[0x7F ^ uval] - 1);
+    }
+
+    public static int encode2ULaw(short[] src, int srcsize, byte[] dest, int start) {
+        if (srcsize <= 0 || src == null || src.length < srcsize)
+            return 0;
+        int encsize = srcsize;
+        for (int i = 0; i < encsize; i++)
+            dest[start + i] = (byte)linear2ulaw(src[i]);
+        return encsize + start;
+    }
+
+    public static int encode2ULawExt(byte[] src, int srcsize, byte[] dest, int start) {
+        if (srcsize <= 0 || src == null || src.length < srcsize)
+            return 0;
+        int encsize = srcsize / 2;
+        int val = 0;
+        int val_ = 0;
+        for (int i = 0; i < encsize; i++) {
+            val = src[2 * i + 1];
+            val_ = src[2 * i];
+            val = val << 8 & 0xFFFFFF00;
+            val_ &= 0xFF;
+            val |= val_;
+            dest[start + i] = (byte)linear2ulaw(val);
+        }
+        return encsize + start;
+    }
+
+    public static int encode2ALaw(short[] src, int srcsize, byte[] dest, int start) {
+        if (srcsize <= 0 || src == null || src.length < srcsize)
+            return 0;
+        int encsize = srcsize;
+        for (int i = 0; i < encsize; i++)
+            dest[start + i] = (byte)linear2alaw(src[i]);
+        return encsize + start;
+    }
+
+    public static int encode2ALawExt(byte[] src, int srcsize, byte[] dest, int start) {
+        if (srcsize <= 0 || src == null || src.length < srcsize)
+            return 0;
+        int encsize = srcsize / 2;
+        int val = 0;
+        int val_ = 0;
+        for (int i = 0; i < encsize; i++) {
+            val = src[2 * i + 1];
+            val_ = src[2 * i];
+            val = val << 8 & 0xFFFFFF00;
+            val_ &= 0xFF;
+            val |= val_;
+            dest[start + i] = (byte)linear2alaw(val);
+        }
+        return encsize + start;
+    }
+
+    public static short[] decodeULaw(byte[] src, int start, int srcsize) {
+        if (srcsize <= 0 || src == null || src.length < srcsize)
+            return null;
+        short[] decbuffer = new short[srcsize];
+        for (int i = 0; i < srcsize; i++)
+            decbuffer[i] = (short)ulaw2linear(src[i + start] & 0xFF);
+        return decbuffer;
+    }
+
+    public static byte[] decodeULawExt(byte[] src, int start, int srcsize) {
+        if (srcsize <= 0 || src == null || src.length < srcsize)
+            return null;
+        byte[] decbuffer = new byte[srcsize * 2];
+        int val = 0;
+        for (int i = 0; i < srcsize; i++) {
+            val = ulaw2linear(src[i + start] & 0xFF);
+            decbuffer[2 * i + 1] = (byte)(val >> 8);
+            decbuffer[2 * i] = (byte)(val << 24 >> 24);
+        }
+        return decbuffer;
+    }
+
+    public static boolean decodeULawExt(byte[] src, int start, int srcsize, byte[] decbuffer) {
+        if (srcsize <= 0 || src == null || src.length < srcsize)
+            return false;
+        int val = 0;
+        for (int i = 0; i < srcsize; i++) {
+            val = ulaw2linear(src[i + start] & 0xFF);
+            decbuffer[2 * i + 1] = (byte)(val >> 8);
+            decbuffer[2 * i] = (byte)(val << 24 >> 24);
+        }
+        return true;
+    }
+
+    public static short[] decodeALaw(byte[] src, int start, int srcsize) {
+        if (srcsize <= 0 || src == null || src.length < srcsize)
+            return null;
+        short[] decbuffer = new short[srcsize];
+        for (int i = 0; i < srcsize; i++)
+            decbuffer[i] = (short)alaw2linear(src[i + start] & 0xFF);
+        return decbuffer;
+    }
+
+    public static byte[] decodeALawExt(byte[] src, int start, int srcsize) {
+        if (srcsize <= 0 || src == null || src.length < srcsize)
+            return null;
+        byte[] decbuffer = new byte[srcsize * 2];
+        int val = 0;
+        for (int i = 0; i < srcsize; i++) {
+            val = alaw2linear(src[i + start] & 0xFF);
+            decbuffer[2 * i + 1] = (byte)(val >> 8);
+            decbuffer[2 * i] = (byte)(val << 24 >> 24);
+        }
+        return decbuffer;
+    }
+
+    public static boolean decodeALawExt(byte[] src, int start, int srcsize, byte[] decbuffer) {
+        if (srcsize <= 0 || src == null || src.length < srcsize)
+            return false;
+        int val = 0;
+        for (int i = 0; i < srcsize; i++) {
+            val = alaw2linear(src[i + start] & 0xFF);
+            decbuffer[2 * i + 1] = (byte)(val >> 8);
+            decbuffer[2 * i] = (byte)(val << 24 >> 24);
+        }
+        return true;
+    }
+
+    public static boolean mixPCMLinear(byte[] src1, byte[] src2, int srcsize, byte[] dest) {
+        if (srcsize <= 0 || src1 == null || src1.length < srcsize ||
+                src2 == null || src2.length < srcsize)
+            return false;
+        int encsize = srcsize / 2;
+        int val = 0;
+        int val_ = 0;
+        int val_final = 0;
+        for (int i = 0; i < encsize; i++) {
+            val = src1[2 * i + 1];
+            val_ = src1[2 * i];
+            val = val << 8 & 0xFFFFFF00;
+            val_ &= 0xFF;
+            val |= val_;
+            val_final = val;
+            val = 0;
+            val_ = 0;
+            val = src2[2 * i + 1];
+            val_ = src2[2 * i];
+            val = val << 8 & 0xFFFFFF00;
+            val_ &= 0xFF;
+            val |= val_;
+            val_final = (int)((val + val_final) / 2.0F);
+            dest[2 * i + 1] = (byte)(val_final >> 8);
+            dest[2 * i] = (byte)(val_final << 24 >> 24);
+        }
+        return true;
+    }
+
+    public static boolean amplitudePCMLinear(byte[] src, int srcsize, int rate) {
+        if (srcsize <= 0 || src == null || src.length < srcsize)
+            return false;
+        int encsize = srcsize / 2;
+        int val = 0;
+        int val_ = 0;
+        int val_final = 0;
+        for (int i = 0; i < encsize; i++) {
+            val = src[2 * i + 1];
+            val_ = src[2 * i];
+            val = val << 8 & 0xFFFFFF00;
+            val_ &= 0xFF;
+            val |= val_;
+            val_final = val / 10 * rate;
+            src[2 * i + 1] = (byte)(val_final >> 8);
+            src[2 * i] = (byte)(val_final << 24 >> 24);
+        }
+        return true;
+    }
+
+    public static boolean getPCMLinearComportableNoise(byte[] src, int srcsize) {
+        if (srcsize <= 0 || src == null || src.length < srcsize)
+            return false;
+        int encsize = srcsize / 2;
+        int val_final = 0;
+        int val = 0;
+        for (int i = 0; i < encsize; i++) {
+            val = 1;
+            val_final = Math.abs(val) % 10;
+            if (i % 2 == 1)
+                val_final *= -1;
+            src[2 * i + 1] = (byte)(val_final >> 8);
+            src[2 * i] = (byte)(val_final << 24 >> 24);
+        }
+        return true;
+    }
+}

+ 225 - 0
WallPadCall/src/main/java/bssoft/stack/sip/SIPHeader.java

@@ -0,0 +1,225 @@
+package bssoft.stack.sip;
+
+import java.util.StringTokenizer;
+
+public class SIPHeader {
+    public String header = null;
+
+    public String headerValue = null;
+
+    public int headerType = SIPStack.SIP_HEADERTYPE_NONE;
+
+    public boolean flag = false;
+
+    public SIPHeader(String message, int headerType) {
+        String compactKeyWord = null;
+        if (message != null) {
+            String keyWord;
+            if (headerType == SIPStack.SIP_HEADERTYPE_ACCEPT) {
+                keyWord = "Accept: ";
+            } else if (headerType == SIPStack.SIP_HEADERTYPE_ACCEPTENCODING) {
+                keyWord = "Accept-Encoding: ";
+            } else if (headerType == SIPStack.SIP_HEADERTYPE_ACCEPTLANGUAGE) {
+                keyWord = "Accept-Language: ";
+            } else if (headerType == SIPStack.SIP_HEADERTYPE_ALERTINFO) {
+                keyWord = "Alert-Info: ";
+            } else if (headerType == SIPStack.SIP_HEADERTYPE_ALLOW) {
+                keyWord = "Allow: ";
+            } else if (headerType == SIPStack.SIP_HEADERTYPE_ALLOWEVENTS) {
+                keyWord = "Allow-Events: ";
+            } else if (headerType == SIPStack.SIP_HEADERTYPE_AUTHENTICATIONINFO) {
+                keyWord = "Authentication-Info: ";
+            } else if (headerType == SIPStack.SIP_HEADERTYPE_AUTHORIZATION) {
+                keyWord = "Authorization: ";
+            } else if (headerType == SIPStack.SIP_HEADERTYPE_CALLID) {
+                keyWord = "Call-ID: ";
+                compactKeyWord = "i: ";
+            } else if (headerType == SIPStack.SIP_HEADERTYPE_CALLINFO) {
+                keyWord = "Call-Info: ";
+            } else if (headerType == SIPStack.SIP_HEADERTYPE_CONTACT) {
+                keyWord = "Contact: ";
+                compactKeyWord = "m: ";
+            } else if (headerType == SIPStack.SIP_HEADERTYPE_CONTENTDISPOSITION) {
+                keyWord = "Content-Disposition: ";
+            } else if (headerType == SIPStack.SIP_HEADERTYPE_CONTENTENCODING) {
+                keyWord = "Content-Encoding: ";
+            } else if (headerType == SIPStack.SIP_HEADERTYPE_CONTENTLANGUAGE) {
+                keyWord = "Content-Language: ";
+            } else if (headerType == SIPStack.SIP_HEADERTYPE_CONTENTLENGTH) {
+                keyWord = "Content-Length: ";
+                compactKeyWord = "l: ";
+            } else if (headerType == SIPStack.SIP_HEADERTYPE_CONTENTTYPE) {
+                keyWord = "Content-Type: ";
+                compactKeyWord = "c: ";
+            } else if (headerType == SIPStack.SIP_HEADERTYPE_CSEQ) {
+                keyWord = "CSeq: ";
+            } else if (headerType == SIPStack.SIP_HEADERTYPE_DATE) {
+                keyWord = "Date: ";
+            } else if (headerType == SIPStack.SIP_HEADERTYPE_EVENT) {
+                keyWord = "Event: ";
+            } else if (headerType == SIPStack.SIP_HEADERTYPE_ERRORINFO) {
+                keyWord = "Error-Info: ";
+            } else if (headerType == SIPStack.SIP_HEADERTYPE_EXPIRES) {
+                keyWord = "Expires: ";
+            } else if (headerType == SIPStack.SIP_HEADERTYPE_FROM) {
+                keyWord = "From: ";
+                compactKeyWord = "f: ";
+            } else if (headerType == SIPStack.SIP_HEADERTYPE_INREPLYTO) {
+                keyWord = "In-Reply-To: ";
+            } else if (headerType == SIPStack.SIP_HEADERTYPE_MAXFORWARDS) {
+                keyWord = "Max-Forwards: ";
+            } else if (headerType == SIPStack.SIP_HEADERTYPE_MINEXPIRES) {
+                keyWord = "Min-Expires: ";
+            } else if (headerType == SIPStack.SIP_HEADERTYPE_MIMEVERSION) {
+                keyWord = "MIME-Version: ";
+            } else if (headerType == SIPStack.SIP_HEADERTYPE_ORGANIZATION) {
+                keyWord = "Organization: ";
+            } else if (headerType == SIPStack.SIP_HEADERTYPE_PRIORITY) {
+                keyWord = "Priority: ";
+            } else if (headerType == SIPStack.SIP_HEADERTYPE_PROXYAUTHENTICATE) {
+                keyWord = "Proxy-Authenticate: ";
+            } else if (headerType == SIPStack.SIP_HEADERTYPE_PROXYAUTHORIZATION) {
+                keyWord = "Proxy-Authorization: ";
+            } else if (headerType == SIPStack.SIP_HEADERTYPE_PROXYREQUIRE) {
+                keyWord = "Proxy-Require: ";
+            } else if (headerType == SIPStack.SIP_HEADERTYPE_PASSERTEDIDENTITY) {
+                keyWord = "P-Asserted-Identity: ";
+            } else if (headerType == SIPStack.SIP_HEADERTYPE_RECORDROUTE) {
+                keyWord = "Record-Route: ";
+            } else if (headerType == SIPStack.SIP_HEADERTYPE_REPLYTO) {
+                keyWord = "Reply-To: ";
+            } else if (headerType == SIPStack.SIP_HEADERTYPE_REQUIRE) {
+                keyWord = "Require: ";
+            } else if (headerType == SIPStack.SIP_HEADERTYPE_RETRYAFTER) {
+                keyWord = "Retry-After: ";
+            } else if (headerType == SIPStack.SIP_HEADERTYPE_ROUTE) {
+                keyWord = "Route: ";
+            } else if (headerType == SIPStack.SIP_HEADERTYPE_SERVER) {
+                keyWord = "Server: ";
+            } else if (headerType == SIPStack.SIP_HEADERTYPE_SUBJECT) {
+                keyWord = "Subject: ";
+            } else if (headerType == SIPStack.SIP_HEADERTYPE_SUPPORTED) {
+                keyWord = "Supported: ";
+            } else if (headerType == SIPStack.SIP_HEADERTYPE_TIMESTAMP) {
+                keyWord = "Timestamp: ";
+            } else if (headerType == SIPStack.SIP_HEADERTYPE_TO) {
+                keyWord = "To: ";
+                compactKeyWord = "t: ";
+            } else if (headerType == SIPStack.SIP_HEADERTYPE_UNSUPPORTED) {
+                keyWord = "Unsupported: ";
+            } else if (headerType == SIPStack.SIP_HEADERTYPE_USERAGENT) {
+                keyWord = "User-Agent: ";
+            } else if (headerType == SIPStack.SIP_HEADERTYPE_VIA) {
+                keyWord = "Via: ";
+                compactKeyWord = "v: ";
+            } else if (headerType == SIPStack.SIP_HEADERTYPE_WARNING) {
+                keyWord = "Warning: ";
+            } else if (headerType == SIPStack.SIP_HEADERTYPE_WWWAUTHENTICATE) {
+                keyWord = "WWW-Authenticate: ";
+            } else if (headerType == SIPStack.SIP_HEADERTYPE_WwwAUTHENTICATE) {
+                keyWord = "Www-Authenticate: ";
+            } else {
+                keyWord = null;
+            }
+            if (keyWord != null) {
+                int iS = message.indexOf(keyWord);
+                int iE = 0;
+                if (iS >= 0) {
+                    iE = message.indexOf(SIPStack.SIP_LINE_END, iS);
+                    if (iE > 0) {
+                        this.header = message.substring(iS, iE);
+                        this.headerValue = message.substring(iS + keyWord.length(), iE);
+                        this.headerType = headerType;
+                        this.flag = true;
+                    }
+                } else {
+                    this.flag = false;
+                }
+            }
+            if (!this.flag && compactKeyWord != null) {
+                int iS = message.indexOf(compactKeyWord);
+                int iE = 0;
+                if (iS >= 0) {
+                    iE = message.indexOf(SIPStack.SIP_LINE_END, iS);
+                    if (iE > 0) {
+                        this.header = message.substring(iS, iE);
+                        this.headerValue = message.substring(iS + compactKeyWord.length(), iE);
+                        this.headerType = headerType;
+                        this.flag = true;
+                    }
+                } else {
+                    this.flag = false;
+                }
+            }
+        }
+    }
+
+    public int callSequenceNumber() {
+        int seqCode = 0;
+        if (this.headerType == SIPStack.SIP_HEADERTYPE_CSEQ && this.header != null && this.header.length() > 0) {
+            StringTokenizer tokenArray = new StringTokenizer(this.header, " ", true);
+            int tokenCount = 0;
+            while (tokenArray.hasMoreTokens()) {
+                String token = tokenArray.nextToken();
+                if (token.length() > 0 && token.compareTo(" ") != 0) {
+                    tokenCount++;
+                    if (tokenCount == 2) {
+                        seqCode = Integer.parseInt(token);
+                        break;
+                    }
+                }
+            }
+        }
+        return seqCode;
+    }
+
+    public String getTag() {
+        String tag = null;
+        if ((this.headerType == SIPStack.SIP_HEADERTYPE_FROM || this.headerType == SIPStack.SIP_HEADERTYPE_TO) &&
+                this.header != null && this.header.length() > 0) {
+            StringTokenizer tokenArray = new StringTokenizer(this.header, ";", true);
+            while (tokenArray.hasMoreTokens()) {
+                String token = tokenArray.nextToken();
+                if (token.length() > 0 && token.startsWith("tag=")) {
+                    tag = token.substring(4);
+                    break;
+                }
+            }
+        }
+        return tag;
+    }
+
+    public String getId() {
+        String id = "";
+        if ((this.headerType == SIPStack.SIP_HEADERTYPE_FROM || this.headerType == SIPStack.SIP_HEADERTYPE_TO) &&
+                this.header != null && this.header.length() > 0) {
+            int iS = 0;
+            int iE = 0;
+            iS = this.header.indexOf("sip:");
+            if (iS > 0) {
+                iE = this.header.indexOf("@", iS);
+                if (iE > 0)
+                    id = this.header.substring(iS + 4, iE).trim();
+            }
+        }
+        return id;
+    }
+
+    public String getFieldValue(String fieldName) {
+        if (this.headerValue == null || this.headerValue.length() <= 0)
+            return null;
+        if (fieldName == null || fieldName.length() <= 0)
+            return null;
+        StringTokenizer tokenArray = new StringTokenizer(this.headerValue, ";><", true);
+        String keyWord = String.valueOf(fieldName) + "=";
+        String fieldValue = null;
+        while (tokenArray.hasMoreTokens()) {
+            String token = tokenArray.nextToken().trim();
+            if (token.length() > 0 && token.startsWith(keyWord)) {
+                fieldValue = token.substring(keyWord.length());
+                break;
+            }
+        }
+        return fieldValue;
+    }
+}

+ 268 - 0
WallPadCall/src/main/java/bssoft/stack/sip/SIPHeaderParty.java

@@ -0,0 +1,268 @@
+package bssoft.stack.sip;
+
+public class SIPHeaderParty {
+    public String header = null;
+
+    public String headerValue = null;
+
+    public String display = null;
+
+    public String username = null;
+
+    public String sipuri = null;
+
+    public String uriusertag = null;
+
+    public String ip = null;
+
+    public int port = 0;
+
+    public String tag = null;
+
+    public int headerType = SIPStack.SIP_HEADERTYPE_NONE;
+
+    public boolean flag = false;
+
+    public SIPHeaderParty(String message, int headerType) {
+        String compactKeyWord = null;
+        if (message != null) {
+            String keyWord;
+            if (headerType == SIPStack.SIP_HEADERTYPE_FROM) {
+                keyWord = "From: ";
+                compactKeyWord = "f: ";
+            } else if (headerType == SIPStack.SIP_HEADERTYPE_TO) {
+                keyWord = "To: ";
+                compactKeyWord = "t: ";
+            } else {
+                keyWord = null;
+            }
+            if (keyWord != null) {
+                int iS = message.indexOf(keyWord);
+                int iE = 0;
+                if (iS >= 0) {
+                    iE = message.indexOf(SIPStack.SIP_LINE_END, iS);
+                    if (iE > 0) {
+                        this.header = message.substring(iS, iE);
+                        this.headerValue = message.substring(iS + keyWord.length(), iE);
+                        this.headerType = headerType;
+                        iE = this.headerValue.indexOf("<sip:");
+                        if (iE > 0) {
+                            String str = null;
+                            str = this.headerValue.substring(0, iE).trim();
+                            if (str != null && str.length() > 1 &&
+                                    str.startsWith("\"") &&
+                                    str.endsWith("\"")) {
+                                this.display = str.substring(1, str.length() - 1);
+                            } else if (str != null && str.length() > 0) {
+                                this.display = str;
+                            }
+                        }
+                        iS = this.headerValue.indexOf("sip:");
+                        if (iS > 0) {
+                            String str = null;
+                            iE = this.headerValue.indexOf(">", iS + 4);
+                            if (iE < 0)
+                                iE = this.headerValue.indexOf(";", iS + 4);
+                            if (iE > 0) {
+                                str = this.headerValue.substring(iS, iE);
+                            } else {
+                                str = this.headerValue.substring(iS);
+                            }
+                            if (str != null && str.length() > 0)
+                                this.sipuri = str.trim();
+                        }
+                        if (this.sipuri != null && this.sipuri.length() > 0) {
+                            iS = this.sipuri.indexOf("@", 4);
+                            if (iS > 0)
+                                this.username = this.sipuri.substring(4, iS).trim();
+                        }
+                        if (this.sipuri != null && this.sipuri.length() > 0) {
+                            iS = this.sipuri.indexOf("@", 4);
+                            String str = null;
+                            if (iS >= 0) {
+                                str = this.sipuri.substring(iS + 1).trim();
+                            } else {
+                                str = this.sipuri.substring(4).trim();
+                            }
+                            this.port = 5060;
+                            if (str != null && str.length() > 0) {
+                                iS = str.indexOf(":");
+                                if (iS > 0) {
+                                    this.port = Integer.parseInt(str.substring(iS + 1).trim());
+                                    this.ip = str.substring(0, iS);
+                                } else {
+                                    this.ip = str;
+                                }
+                            }
+                        }
+                        iS = this.headerValue.indexOf(";tag=");
+                        if (iS > 0) {
+                            String str = null;
+                            iE = this.headerValue.indexOf(";", iS + 5);
+                            if (iE >= 0) {
+                                if (iE > iS + 5) {
+                                    str = this.headerValue.substring(iS + 5, iE);
+                                } else {
+                                    str = "";
+                                }
+                            } else {
+                                str = this.headerValue.substring(iS + 5);
+                            }
+                            if (str != null && str.length() > 0)
+                                this.tag = str.trim();
+                        } else {
+                            this.tag = "";
+                        }
+                        iS = this.headerValue.indexOf("sip:");
+                        if (iS > 0) {
+                            String str = null;
+                            iE = this.headerValue.indexOf(">", iS + 4);
+                            if (iE > 0)
+                                str = this.headerValue.substring(iS, iE);
+                            if (str != null && str.length() > 0) {
+                                iS = str.indexOf(";user=", iS + 4);
+                                if (iS > 0) {
+                                    this.uriusertag = str.substring(iS + 6);
+                                    if (this.uriusertag != null && this.uriusertag.length() > 0 && this.uriusertag.indexOf(";") >= 0)
+                                        if (this.uriusertag.indexOf(";") == 0) {
+                                            this.uriusertag = null;
+                                        } else {
+                                            this.uriusertag = this.uriusertag.substring(0, this.uriusertag.indexOf(";")).trim();
+                                        }
+                                }
+                            }
+                        }
+                        this.flag = true;
+                    }
+                }
+            } else if (compactKeyWord != null) {
+                int iS = message.indexOf(compactKeyWord);
+                int iE = 0;
+                if (iS >= 0) {
+                    iE = message.indexOf(SIPStack.SIP_LINE_END, iS);
+                    if (iE > 0) {
+                        this.header = message.substring(iS, iE);
+                        this.headerValue = message.substring(iS + compactKeyWord.length(), iE);
+                        this.headerType = headerType;
+                        iE = this.headerValue.indexOf("<sip:");
+                        if (iE > 0) {
+                            String str = null;
+                            str = this.headerValue.substring(0, iE).trim();
+                            if (str != null && str.length() > 1 &&
+                                    str.startsWith("\"") &&
+                                    str.endsWith("\"")) {
+                                this.display = str.substring(1, str.length() - 1);
+                            } else if (str != null && str.length() > 0) {
+                                this.display = str;
+                            }
+                        }
+                        iS = this.headerValue.indexOf("sip:");
+                        if (iS > 0) {
+                            String str = null;
+                            iE = this.headerValue.indexOf(">", iS + 4);
+                            if (iE < 0)
+                                iE = this.headerValue.indexOf(";", iS + 4);
+                            if (iE > 0) {
+                                str = this.headerValue.substring(iS, iE);
+                            } else {
+                                str = this.headerValue.substring(iS);
+                            }
+                            if (str != null && str.length() > 0)
+                                this.sipuri = str.trim();
+                        }
+                        if (this.sipuri != null && this.sipuri.length() > 0) {
+                            iS = this.sipuri.indexOf("@", 4);
+                            if (iS > 0)
+                                this.username = this.sipuri.substring(4, iS).trim();
+                        }
+                        if (this.sipuri != null && this.sipuri.length() > 0) {
+                            iS = this.sipuri.indexOf("@", 4);
+                            String str = null;
+                            if (iS >= 0) {
+                                str = this.sipuri.substring(iS + 1).trim();
+                            } else {
+                                str = this.sipuri.substring(4).trim();
+                            }
+                            this.port = 5060;
+                            if (str != null && str.length() > 0) {
+                                iS = str.indexOf(":");
+                                if (iS > 0) {
+                                    this.port = Integer.parseInt(str.substring(iS + 1).trim());
+                                    this.ip = str.substring(0, iS);
+                                } else {
+                                    this.ip = str;
+                                }
+                            }
+                        }
+                        iS = this.headerValue.indexOf(";tag=");
+                        if (iS > 0) {
+                            String str = null;
+                            iE = this.headerValue.indexOf(";", iS + 5);
+                            if (iE >= 0) {
+                                if (iE > iS + 5) {
+                                    str = this.headerValue.substring(iS + 5, iE);
+                                } else {
+                                    str = "";
+                                }
+                            } else {
+                                str = this.headerValue.substring(iS + 5);
+                            }
+                            if (str != null && str.length() > 0)
+                                this.tag = str.trim();
+                        } else {
+                            this.tag = "";
+                        }
+                        iS = this.headerValue.indexOf("sip:");
+                        if (iS > 0) {
+                            String str = null;
+                            iE = this.headerValue.indexOf(">", iS + 4);
+                            if (iE > 0)
+                                str = this.headerValue.substring(iS, iE);
+                            if (str != null && str.length() > 0) {
+                                iS = str.indexOf(";user=", iS + 4);
+                                if (iS > 0) {
+                                    this.uriusertag = str.substring(iS + 6);
+                                    if (this.uriusertag != null && this.uriusertag.length() > 0 && this.uriusertag.indexOf(";") >= 0)
+                                        if (this.uriusertag.indexOf(";") == 0) {
+                                            this.uriusertag = null;
+                                        } else {
+                                            this.uriusertag = this.uriusertag.substring(0, this.uriusertag.indexOf(";")).trim();
+                                        }
+                                }
+                            }
+                        }
+                        this.flag = true;
+                    }
+                }
+            }
+        }
+    }
+
+    public String getDisplay() {
+        return this.display;
+    }
+
+    public String getUsername() {
+        return this.username;
+    }
+
+    public String getSipuri() {
+        return this.sipuri;
+    }
+
+    public String getSipuriusertag() {
+        return this.uriusertag;
+    }
+
+    public String getIp() {
+        return this.ip;
+    }
+
+    public int getPort() {
+        return this.port;
+    }
+
+    public String getTag() {
+        return this.tag;
+    }
+}

+ 135 - 0
WallPadCall/src/main/java/bssoft/stack/sip/SIPROUTEHeader.java

@@ -0,0 +1,135 @@
+package bssoft.stack.sip;
+
+public class SIPROUTEHeader {
+    public String header = null;
+
+    public String headerValue = null;
+
+    public String username = null;
+
+    public String sipuri = null;
+
+    public String uriusertag = null;
+
+    public String ip = null;
+
+    public int port = 0;
+
+    public String tag = null;
+
+    public boolean flag = false;
+
+    public SIPROUTEHeader(String header) {
+        int iS = 0;
+        int iE = 0;
+        if (header != null && header.length() > 0 && header.startsWith("Route: ")) {
+            this.header = header;
+            this.headerValue = header.substring(7).trim();
+            if (this.headerValue != null && this.headerValue.length() > 0) {
+                iS = this.headerValue.indexOf("sip:");
+                if (iS > 0) {
+                    String str = null;
+                    iE = this.headerValue.indexOf(">", iS + 4);
+                    if (iE < 0)
+                        iE = this.headerValue.indexOf(";", iS + 4);
+                    if (iE > 0) {
+                        str = this.headerValue.substring(iS, iE);
+                    } else {
+                        str = this.headerValue.substring(iS);
+                    }
+                    if (str != null && str.length() > 0)
+                        this.sipuri = str.trim();
+                }
+                if (this.sipuri != null && this.sipuri.length() > 0) {
+                    iS = this.sipuri.indexOf("@", 4);
+                    if (iS > 0)
+                        this.username = this.sipuri.substring(4, iS).trim();
+                }
+                if (this.sipuri != null && this.sipuri.length() > 0) {
+                    iS = this.sipuri.indexOf("@", 4);
+                    iE = this.sipuri.indexOf(";", 4);
+                    String str = null;
+                    if (iS >= 0 && iE >= 0) {
+                        str = this.sipuri.substring(iS + 1, iE).trim();
+                    } else if (iS >= 0) {
+                        str = this.sipuri.substring(iS + 1).trim();
+                    } else if (iE >= 0) {
+                        str = this.sipuri.substring(4, iE).trim();
+                    } else {
+                        str = this.sipuri.substring(4).trim();
+                    }
+                    this.port = 5060;
+                    if (str != null && str.length() > 0) {
+                        iS = str.indexOf(":");
+                        if (iS > 0) {
+                            this.port = Integer.parseInt(str.substring(iS + 1).trim());
+                            this.ip = str.substring(0, iS);
+                        } else {
+                            this.ip = str;
+                        }
+                    }
+                }
+                iS = this.headerValue.indexOf(";tag=");
+                if (iS > 0) {
+                    String str = null;
+                    iE = this.headerValue.indexOf(";", iS + 5);
+                    if (iE >= 0) {
+                        if (iE > iS + 5) {
+                            str = this.headerValue.substring(iS + 5, iE);
+                        } else {
+                            str = "";
+                        }
+                    } else {
+                        str = this.headerValue.substring(iS + 5);
+                    }
+                    if (str != null && str.length() > 0)
+                        this.tag = str.trim();
+                }
+                iS = this.headerValue.indexOf("sip:");
+                if (iS > 0) {
+                    String str = null;
+                    iE = this.headerValue.indexOf(">", iS + 4);
+                    if (iE > 0)
+                        str = this.headerValue.substring(iS, iE);
+                    if (str != null && str.length() > 0) {
+                        iS = str.indexOf(";user=", iS + 4);
+                        if (iS > 0) {
+                            this.uriusertag = str.substring(iS + 6);
+                            if (this.uriusertag != null && this.uriusertag.length() > 0 && this.uriusertag.indexOf(";") >= 0)
+                                if (this.uriusertag.indexOf(";") == 0) {
+                                    this.uriusertag = null;
+                                } else {
+                                    this.uriusertag = this.uriusertag.substring(0, this.uriusertag.indexOf(";")).trim();
+                                }
+                        }
+                    }
+                }
+                this.flag = true;
+            }
+        }
+    }
+
+    public String getUsername() {
+        return this.username;
+    }
+
+    public String getSipuri() {
+        return this.sipuri;
+    }
+
+    public String getSipuriusertag() {
+        return this.uriusertag;
+    }
+
+    public String getIp() {
+        return this.ip;
+    }
+
+    public int getPort() {
+        return this.port;
+    }
+
+    public String getTag() {
+        return this.tag;
+    }
+}

+ 204 - 0
WallPadCall/src/main/java/bssoft/stack/sip/SIPRequestLine.java

@@ -0,0 +1,204 @@
+package bssoft.stack.sip;
+
+import android.util.Log;
+
+import java.util.StringTokenizer;
+
+public class SIPRequestLine {
+    public String header = null;
+
+    public int iMethodType = SIPStack.SIP_METHODTYPE_NONE;
+
+    public String uri = null;
+
+    public int version = 2;
+
+    public int revision = 0;
+
+    public int code = 0;
+
+    public int iMessageType = SIPStack.SIP_MSGTYPE_NONE;
+
+    public boolean flag = false;
+
+    public SIPRequestLine(String message) {
+        if (message != null) {
+            StringTokenizer st = new StringTokenizer(message, "\n", true);
+            int headerCount = 0;
+            while (st.hasMoreTokens()) {
+                this.header = st.nextToken();
+                if (this.header.length() > 1) {
+                    if (headerCount == 0 && this.header.startsWith("INVITE") && this.header.endsWith("SIP/2.0\r")) {
+                        this.iMessageType = SIPStack.SIP_MSGTYPE_REQUEST;
+                        this.iMethodType = SIPStack.SIP_METHODTYPE_INVITE;
+                        this.flag = true;
+                        break;
+                    }
+                    if (headerCount == 0 && this.header.startsWith("BYE") && this.header.endsWith("SIP/2.0\r")) {
+                        this.iMessageType = SIPStack.SIP_MSGTYPE_REQUEST;
+                        this.iMethodType = SIPStack.SIP_METHODTYPE_BYE;
+                        this.flag = true;
+                        break;
+                    }
+                    if (headerCount == 0 && this.header.startsWith("ACK") && this.header.endsWith("SIP/2.0\r")) {
+                        this.iMessageType = SIPStack.SIP_MSGTYPE_REQUEST;
+                        this.iMethodType = SIPStack.SIP_METHODTYPE_ACK;
+                        this.flag = true;
+                        break;
+                    }
+                    if (headerCount == 0 && this.header.startsWith("CANCEL") && this.header.endsWith("SIP/2.0\r")) {
+                        this.iMessageType = SIPStack.SIP_MSGTYPE_REQUEST;
+                        this.iMethodType = SIPStack.SIP_METHODTYPE_CANCEL;
+                        this.flag = true;
+                        break;
+                    }
+                    if (headerCount == 0 && this.header.startsWith("OPTIONS") && this.header.endsWith("SIP/2.0\r")) {
+                        this.iMessageType = SIPStack.SIP_MSGTYPE_REQUEST;
+                        this.iMethodType = SIPStack.SIP_METHODTYPE_OPTIONS;
+                        this.flag = true;
+                        break;
+                    }
+                    if (headerCount == 0 && this.header.startsWith("INFO") && this.header.endsWith("SIP/2.0\r")) {
+                        this.iMessageType = SIPStack.SIP_MSGTYPE_REQUEST;
+                        this.iMethodType = SIPStack.SIP_METHODTYPE_INFO;
+                        this.flag = true;
+                        break;
+                    }
+                    if (headerCount == 0 && this.header.startsWith("PRACK") && this.header.endsWith("SIP/2.0\r")) {
+                        this.iMessageType = SIPStack.SIP_MSGTYPE_REQUEST;
+                        this.iMethodType = SIPStack.SIP_METHODTYPE_PRACK;
+                        this.flag = true;
+                        break;
+                    }
+                    if (headerCount == 0 && this.header.startsWith("MESSAGE") && this.header.endsWith("SIP/2.0\r")) {
+                        this.iMessageType = SIPStack.SIP_MSGTYPE_REQUEST;
+                        this.iMethodType = SIPStack.SIP_METHODTYPE_MESSAGE;
+                        this.flag = true;
+                        break;
+                    }
+                    if (headerCount == 0 && this.header.startsWith("SUBSCRIBE") && this.header.endsWith("SIP/2.0\r")) {
+                        this.iMessageType = SIPStack.SIP_MSGTYPE_REQUEST;
+                        this.iMethodType = SIPStack.SIP_METHODTYPE_SUBSCRIBE;
+                        break;
+                    }
+                    if (headerCount == 0 && this.header.startsWith("REFER") && this.header.endsWith("SIP/2.0\r")) {
+                        this.iMessageType = SIPStack.SIP_MSGTYPE_REQUEST;
+                        this.iMethodType = SIPStack.SIP_METHODTYPE_REFER;
+                        break;
+                    }
+                    if (headerCount == 0 && this.header.startsWith("NOTIFY") && this.header.endsWith("SIP/2.0\r")) {
+                        this.iMessageType = SIPStack.SIP_MSGTYPE_REQUEST;
+                        this.iMethodType = SIPStack.SIP_METHODTYPE_NOTIFY;
+                        break;
+                    }
+                    if (headerCount == 0 && this.header.startsWith("PUBLISH") && this.header.endsWith("SIP/2.0\r")) {
+                        this.iMessageType = SIPStack.SIP_MSGTYPE_REQUEST;
+                        this.iMethodType = SIPStack.SIP_METHODTYPE_PUBLISH;
+                        break;
+                    }
+                    if (headerCount == 0 && this.header.startsWith("REGISTER") && this.header.endsWith("SIP/2.0\r")) {
+                        this.iMessageType = SIPStack.SIP_MSGTYPE_REQUEST;
+                        this.iMethodType = SIPStack.SIP_METHODTYPE_REGISTER;
+                        this.flag = true;
+                        break;
+                    }
+                    if (headerCount == 0 && this.header.startsWith("SIP/2.0") && this.header.endsWith("\r")) {
+                        this.iMessageType = SIPStack.SIP_MSGTYPE_RESPONSE;
+                        this.iMethodType = SIPStack.SIP_METHODTYPE_NONE;
+                        StringTokenizer tokenArray = new StringTokenizer(this.header, " ", true);
+                        int tokenCount = 0;
+                        //Log.e("INVITEParser", "[INVITEParser] ============ token ============ " + this.header);
+                        String[] strSplit = this.header.split(" ");
+                        this.code = Integer.parseInt(strSplit[1]);
+                        while (tokenArray.hasMoreTokens()) {
+                            String token = tokenArray.nextToken();
+                            //Log.e("INVITEParser", "[INVITEParser] ============ token ============ " + token);
+                            tokenCount++;
+                            if (token.compareTo(" ") != 0 && tokenCount == 2)
+                            //if (tokenCount == 2)
+                                this.code = Integer.parseInt(token);
+                        }
+                        //Log.e("INVITEParser", "[INVITEParser] ============ token  this.code ============ " + this.code);
+                        int iS = message.indexOf("CSeq: ");
+                        int iE = 0;
+                        if (iS >= 0) {
+                            iE = message.indexOf(SIPStack.SIP_LINE_END, iS);
+                            if (iE <= 0)
+                                break;
+                            String strCSEQ = message.substring(iS, iE);
+                            tokenArray = new StringTokenizer(strCSEQ, " ", true);
+                            tokenCount = 0;
+                            while (tokenArray.hasMoreTokens()) {
+                                String token = tokenArray.nextToken();
+                                if (token.length() > 0 && token.compareTo(" ") != 0) {
+                                    tokenCount++;
+                                    if (tokenCount == 3) {
+                                        if (token.compareTo("REGISTER") == 0) {
+                                            this.iMethodType = SIPStack.SIP_METHODTYPE_REGISTER;
+                                        } else if (token.compareTo("INVITE") == 0) {
+                                            this.iMethodType = SIPStack.SIP_METHODTYPE_INVITE;
+                                        } else if (token.compareTo("CANCEL") == 0) {
+                                            this.iMethodType = SIPStack.SIP_METHODTYPE_CANCEL;
+                                        } else if (token.compareTo("BYE") == 0) {
+                                            this.iMethodType = SIPStack.SIP_METHODTYPE_BYE;
+                                        } else if (token.compareTo("INFO") == 0) {
+                                            this.iMethodType = SIPStack.SIP_METHODTYPE_INFO;
+                                        } else if (token.compareTo("OPTIONS") == 0) {
+                                            this.iMethodType = SIPStack.SIP_METHODTYPE_OPTIONS;
+                                        } else if (token.compareTo("ACK") == 0) {
+                                            this.iMethodType = SIPStack.SIP_METHODTYPE_ACK;
+                                        } else if (token.compareTo("REFER") == 0) {
+                                            this.iMethodType = SIPStack.SIP_METHODTYPE_REFER;
+                                        } else if (token.compareTo("NOTIFY") == 0) {
+                                            this.iMethodType = SIPStack.SIP_METHODTYPE_NOTIFY;
+                                        } else if (token.compareTo("PUBLISH") == 0) {
+                                            this.iMethodType = SIPStack.SIP_METHODTYPE_PUBLISH;
+                                        } else if (token.compareTo("MESSAGE") == 0) {
+                                            this.iMethodType = SIPStack.SIP_METHODTYPE_MESSAGE;
+                                        } else if (token.compareTo("SUBSCRIBE") == 0) {
+                                            this.iMethodType = SIPStack.SIP_METHODTYPE_SUBSCRIBE;
+                                        } else if (token.compareTo("PRACK") == 0) {
+                                            this.iMethodType = SIPStack.SIP_METHODTYPE_PRACK;
+                                        }
+                                        if (this.iMethodType != SIPStack.SIP_METHODTYPE_NONE)
+                                            this.flag = true;
+                                        break;
+                                    }
+                                }
+                            }
+                        }
+                        break;
+                    }
+                }
+            }
+            if (this.flag && this.iMessageType == SIPStack.SIP_MSGTYPE_REQUEST && this.header != null) {
+                StringTokenizer tokenArray = new StringTokenizer(this.header, " ", true);
+                int tokenCount = 0;
+                while (tokenArray.hasMoreTokens()) {
+                    String token = tokenArray.nextToken();
+                    if (token.compareTo(" ") == 0)
+                        continue;
+                    tokenCount++;
+                    if (tokenCount == 2)
+                        this.uri = token;
+                }
+            }
+        }
+        //print();
+    }
+
+    public void print() {
+        System.out.println("=====================================================");
+        System.out.println("HEADER:");
+        System.out.println(this.header);
+        System.out.println(".....................................................");
+        System.out.println("flag\t\t:" + this.flag);
+        System.out.println("iMethodType\t:" + this.iMethodType);
+        System.out.println("uri\t\t\t:" + this.uri);
+        System.out.println("code\t\t:" + this.code);
+        System.out.println("version\t\t:" + this.version);
+        System.out.println("revision\t:" + this.revision);
+        System.out.println("iMessageType:" + this.iMessageType);
+        System.out.println("=====================================================");
+    }
+}

+ 248 - 0
WallPadCall/src/main/java/bssoft/stack/sip/SIPSdp.java

@@ -0,0 +1,248 @@
+package bssoft.stack.sip;
+
+import java.util.Date;
+
+public class SIPSdp {
+    public String vH = null;
+
+    public String oH = null;
+
+    public String sH = null;
+
+    public String cH = null;
+
+    public String tH = null;
+
+    public SDPMedia audioM = null;
+
+    public SDPMedia videoM = null;
+
+    public String body = null;
+
+    public String dn = null;
+
+    public String platformIp = null;
+
+    public String audioDescription = null;
+
+    public String videoDescription = null;
+
+    public boolean flag;
+
+    public SIPSdp(String dn, String localIp) {
+        if (!SIPStack.bStackLicensed) {
+            System.out.println("라이슨스키를 설정하세요.");
+                    //System.exit(0);
+        }
+        this.dn = dn;
+        this.platformIp = localIp;
+        long ltime = (new Date()).getTime();
+        this.vH = "v=0" + SIPStack.SIP_LINE_END;
+        this.oH = "o=" + dn + " " + ltime + " " + (ltime + 1L) + " IN IP4 " + this.platformIp + SIPStack.SIP_LINE_END;
+        this.sH = "s=Smart Android call" + SIPStack.SIP_LINE_END;
+        this.cH = "c=IN IP4 " + this.platformIp + SIPStack.SIP_LINE_END;
+        this.tH = "t=0 0" + SIPStack.SIP_LINE_END;
+        this.audioDescription = "";
+        this.videoDescription = "";
+        this.flag = true;
+    }
+
+    public SIPSdp(String dn, String localIp, String localSdpIp) {
+        if (!SIPStack.bStackLicensed) {
+            System.out.println("라이슨스키를 설정하세요.");
+                    //System.exit(0);
+        }
+        this.dn = dn;
+        this.platformIp = localIp;
+        long ltime = (new Date()).getTime();
+        this.vH = "v=0" + SIPStack.SIP_LINE_END;
+        this.oH = "o=" + dn + " " + ltime + " " + (ltime + 1L) + " IN IP4 " + localSdpIp + SIPStack.SIP_LINE_END;
+        this.sH = "s=Smart Android call" + SIPStack.SIP_LINE_END;
+        this.cH = "c=IN IP4 " + localSdpIp + SIPStack.SIP_LINE_END;
+        this.tH = "t=0 0" + SIPStack.SIP_LINE_END;
+        this.audioDescription = "";
+        this.videoDescription = "";
+        this.flag = true;
+    }
+
+    public SIPSdp(String body) {
+        if (!SIPStack.bStackLicensed) {
+            System.out.println("라이슨스키를 설정하세요.");
+                    //System.exit(0);
+        }
+        if (body != null && body.length() > 0) {
+            this.body = body;
+            int iS = 0;
+            int iE = 0;
+            iS = body.indexOf("v=");
+            if (iS >= 0)
+                iE = body.indexOf(SIPStack.SIP_LINE_END, iS);
+            if (iS >= 0 && iE > iS)
+                this.vH = body.substring(iS, iE + 2);
+            iS = 0;
+            iE = 0;
+            iS = body.indexOf("o=");
+            if (iS >= 0)
+                iE = body.indexOf(SIPStack.SIP_LINE_END, iS);
+            if (iS >= 0 && iE > iS)
+                this.oH = body.substring(iS, iE + 2);
+            iS = 0;
+            iE = 0;
+            iS = body.indexOf("s=");
+            if (iS >= 0)
+                iE = body.indexOf(SIPStack.SIP_LINE_END, iS);
+            if (iS >= 0 && iE > iS)
+                this.sH = body.substring(iS, iE + 2);
+            iS = 0;
+            iE = 0;
+            iS = body.indexOf("c=");
+            if (iS >= 0)
+                iE = body.indexOf(SIPStack.SIP_LINE_END, iS);
+            if (iS >= 0 && iE > iS)
+                this.cH = body.substring(iS, iE + 2);
+            iS = 0;
+            iE = 0;
+            iS = body.indexOf("t=");
+            if (iS >= 0)
+                iE = body.indexOf(SIPStack.SIP_LINE_END, iS);
+            if (iS >= 0 && iE > iS)
+                this.tH = body.substring(iS, iE + 2);
+            if (this.vH != null && this.vH.length() > 0 &&
+                    this.oH != null && this.oH.length() > 0 &&
+                    this.tH != null && this.tH.length() > 0) {
+                this.platformIp = "0.0.0.0";
+                if (this.cH != null && this.cH.length() > 0 && this.cH.startsWith("c=IN IP4 ")) {
+                    iE = this.cH.indexOf(SIPStack.SIP_LINE_END);
+                    this.platformIp = this.cH.substring("c=IN IP4 ".length(), iE);
+                }
+                iS = body.indexOf("m=audio ");
+                if (iS > 0) {
+                    iE = body.indexOf("m=", iS + 8);
+                    if (iE > 0 && iE > iS) {
+                        this.audioM = new SDPMedia(body.substring(iS, iE), this.platformIp);
+                    } else if (iE < 0) {
+                        this.audioM = new SDPMedia(body.substring(iS), this.platformIp);
+                    }
+                }
+                iS = body.indexOf("m=video ");
+                if (iS > 0) {
+                    iE = body.indexOf("m=", iS + 8);
+                    if (iE > 0 && iE > iS) {
+                        this.videoM = new SDPMedia(body.substring(iS, iE), this.platformIp);
+                    } else if (iE < 0) {
+                        this.videoM = new SDPMedia(body.substring(iS), this.platformIp);
+                    }
+                }
+            }
+            this.flag = true;
+        }
+    }
+
+    public boolean setMediaPort(int mediaType, int port) {
+        if (mediaType == SIPStack.SIP_MEDIATYPE_AUDIO) {
+            if (this.audioM == null) {
+                this.audioM = new SDPMedia(mediaType);
+                if (this.audioM != null && this.audioM.flag)
+                    return this.audioM.setMediaAddress(this.platformIp, port);
+            }
+        } else if (mediaType == SIPStack.SIP_MEDIATYPE_VIDEO) {
+            if (this.videoM == null) {
+                this.videoM = new SDPMedia(mediaType);
+                if (this.videoM != null && this.videoM.flag)
+                    return this.videoM.setMediaAddress(this.platformIp, port);
+            }
+        }
+        return false;
+    }
+
+    public boolean setCodec(int mediaType, int codec) {
+        if (mediaType == SIPStack.SIP_MEDIATYPE_AUDIO) {
+            if (this.audioM != null && this.audioM.flag)
+                return this.audioM.setCodec(codec);
+        } else if (mediaType == SIPStack.SIP_MEDIATYPE_VIDEO) {
+            if (this.videoM != null && this.videoM.flag)
+                return this.videoM.setCodec(codec);
+        }
+        return false;
+    }
+
+    public boolean setCodec(int mediaType, int codec, String describe) {
+        if (mediaType == SIPStack.SIP_MEDIATYPE_AUDIO) {
+            if (this.audioM != null && this.audioM.flag)
+                return this.audioM.setCodec(codec, describe);
+        } else if (mediaType == SIPStack.SIP_MEDIATYPE_VIDEO) {
+            if (this.videoM != null && this.videoM.flag)
+                return this.videoM.setCodec(codec, describe);
+        }
+        return false;
+    }
+
+    public boolean setFmtpDescribe(int mediaType, int codec, String describe) {
+        if (mediaType == SIPStack.SIP_MEDIATYPE_AUDIO) {
+            if (this.audioM != null && this.audioM.flag)
+                return this.audioM.setFmtpDescribe(codec, describe);
+        } else if (mediaType == SIPStack.SIP_MEDIATYPE_VIDEO) {
+            if (this.videoM != null && this.videoM.flag)
+                return this.videoM.setFmtpDescribe(codec, describe);
+        }
+        return false;
+    }
+
+    public void resetSdp() {
+        this.flag = false;
+    }
+
+    public String getBodyString() {
+        this.audioDescription = "";
+        this.videoDescription = "";
+        if (!this.flag)
+            return null;
+        if (this.audioM != null && this.audioM.flag) {
+            this.audioDescription = this.audioM.getMediaString();
+            if (this.audioDescription == null)
+                this.audioDescription = "";
+        }
+        if (this.videoM != null && this.videoM.flag) {
+            this.videoDescription = this.videoM.getMediaString();
+            if (this.videoDescription == null)
+                this.videoDescription = "";
+        }
+        this.body = String.valueOf(this.vH) +
+                this.oH +
+                this.sH +
+                this.cH +
+                this.tH +
+                this.audioDescription +
+                this.videoDescription;
+        return this.body;
+    }
+
+    public String getFinalBodyString() {
+        this.audioDescription = "";
+        this.videoDescription = "";
+        if (!this.flag)
+            return null;
+        if (this.audioM != null && this.audioM.flag) {
+            this.audioDescription = this.audioM.getFinalMediaString();
+            if (this.audioDescription == null)
+                this.audioDescription = "";
+        }
+        if (this.videoM != null && this.videoM.flag) {
+            this.videoDescription = this.videoM.getFinalMediaString();
+            if (this.videoDescription == null)
+                this.videoDescription = "";
+        }
+        this.body = String.valueOf(this.vH) +
+                this.oH +
+                this.sH +
+                this.cH +
+                this.tH +
+                this.audioDescription +
+                this.videoDescription;
+        return this.body;
+    }
+
+    public boolean update(String body) {
+        return true;
+    }
+}

+ 785 - 0
WallPadCall/src/main/java/bssoft/stack/sip/SIPStack.java

@@ -0,0 +1,785 @@
+package bssoft.stack.sip;
+
+import java.net.InetAddress;
+import java.net.UnknownHostException;
+import java.security.NoSuchAlgorithmException;
+import java.util.Date;
+import java.util.StringTokenizer;
+
+public class SIPStack {
+    public static int SIP_LOCAL_PORT = 5060;
+
+    public static int SIP_SIGNAL_PORT = 5060;
+
+    public static int MAX_SIGNAL_PORTS = 100;
+
+    public static int SIP_METHODTYPE_NONE = 0;
+
+    public static int SIP_METHODTYPE_REGISTER = 1;
+
+    public static int SIP_METHODTYPE_INVITE = 2;
+
+    public static int SIP_METHODTYPE_CANCEL = 3;
+
+    public static int SIP_METHODTYPE_BYE = 4;
+
+    public static int SIP_METHODTYPE_INFO = 5;
+
+    public static int SIP_METHODTYPE_OPTIONS = 6;
+
+    public static int SIP_METHODTYPE_ACK = 7;
+
+    public static int SIP_METHODTYPE_REFER = 8;
+
+    public static int SIP_METHODTYPE_NOTIFY = 9;
+
+    public static int SIP_METHODTYPE_MESSAGE = 10;
+
+    public static int SIP_METHODTYPE_SUBSCRIBE = 11;
+
+    public static int SIP_METHODTYPE_PRACK = 12;
+
+    public static int SIP_METHODTYPE_PUBLISH = 13;
+
+    public static int SIP_METHODTYPE_RESPONSE = 14;
+
+    public static int SIP_HEADERTYPE_NONE = 0;
+
+    public static int SIP_HEADERTYPE_ACCEPT = 1;
+
+    public static int SIP_HEADERTYPE_ACCEPTENCODING = 2;
+
+    public static int SIP_HEADERTYPE_ACCEPTLANGUAGE = 3;
+
+    public static int SIP_HEADERTYPE_ALERTINFO = 4;
+
+    public static int SIP_HEADERTYPE_ALLOW = 5;
+
+    public static int SIP_HEADERTYPE_ALLOWEVENTS = 6;
+
+    public static int SIP_HEADERTYPE_AUTHENTICATIONINFO = 7;
+
+    public static int SIP_HEADERTYPE_AUTHORIZATION = 8;
+
+    public static int SIP_HEADERTYPE_CALLID = 9;
+
+    public static int SIP_HEADERTYPE_CALLINFO = 10;
+
+    public static int SIP_HEADERTYPE_CONTACT = 11;
+
+    public static int SIP_HEADERTYPE_CONTENTDISPOSITION = 12;
+
+    public static int SIP_HEADERTYPE_CONTENTENCODING = 13;
+
+    public static int SIP_HEADERTYPE_CONTENTLANGUAGE = 14;
+
+    public static int SIP_HEADERTYPE_CONTENTLENGTH = 15;
+
+    public static int SIP_HEADERTYPE_CONTENTTYPE = 16;
+
+    public static int SIP_HEADERTYPE_CSEQ = 17;
+
+    public static int SIP_HEADERTYPE_DATE = 18;
+
+    public static int SIP_HEADERTYPE_EVENT = 19;
+
+    public static int SIP_HEADERTYPE_ERRORINFO = 20;
+
+    public static int SIP_HEADERTYPE_EXPIRES = 21;
+
+    public static int SIP_HEADERTYPE_FROM = 22;
+
+    public static int SIP_HEADERTYPE_INREPLYTO = 23;
+
+    public static int SIP_HEADERTYPE_MAXFORWARDS = 24;
+
+    public static int SIP_HEADERTYPE_MINEXPIRES = 25;
+
+    public static int SIP_HEADERTYPE_MIMEVERSION = 26;
+
+    public static int SIP_HEADERTYPE_ORGANIZATION = 27;
+
+    public static int SIP_HEADERTYPE_PRIORITY = 28;
+
+    public static int SIP_HEADERTYPE_PROXYAUTHENTICATE = 29;
+
+    public static int SIP_HEADERTYPE_PROXYAUTHORIZATION = 30;
+
+    public static int SIP_HEADERTYPE_PROXYREQUIRE = 31;
+
+    public static int SIP_HEADERTYPE_PASSERTEDIDENTITY = 32;
+
+    public static int SIP_HEADERTYPE_RECORDROUTE = 33;
+
+    public static int SIP_HEADERTYPE_REPLYTO = 34;
+
+    public static int SIP_HEADERTYPE_REQUIRE = 35;
+
+    public static int SIP_HEADERTYPE_RETRYAFTER = 36;
+
+    public static int SIP_HEADERTYPE_ROUTE = 37;
+
+    public static int SIP_HEADERTYPE_SERVER = 38;
+
+    public static int SIP_HEADERTYPE_SUBJECT = 39;
+
+    public static int SIP_HEADERTYPE_SUPPORTED = 40;
+
+    public static int SIP_HEADERTYPE_TIMESTAMP = 41;
+
+    public static int SIP_HEADERTYPE_TO = 42;
+
+    public static int SIP_HEADERTYPE_UNSUPPORTED = 43;
+
+    public static int SIP_HEADERTYPE_USERAGENT = 44;
+
+    public static int SIP_HEADERTYPE_VIA = 45;
+
+    public static int SIP_HEADERTYPE_WARNING = 46;
+
+    public static int SIP_HEADERTYPE_WWWAUTHENTICATE = 47;
+
+    public static int SIP_HEADERTYPE_WwwAUTHENTICATE = 48;
+
+    public static String SIP_LINE_END = "\r\n";
+
+    public static String SIP_LINE_DOUBLEEND = "\r\n\r\n";
+
+    public static String SIP_LINE_END_SINGLE = "\n";
+
+    public static String USER_AGENT = "BSSHns release 0100o";
+
+    public static int SIP_MSGTYPE_NONE = 0;
+
+    public static int SIP_MSGTYPE_REQUEST = 1;
+
+    public static int SIP_MSGTYPE_RESPONSE = 2;
+
+    public static int SIP_REGSTATE_IDLE = 0;
+
+    public static int SIP_REGSTATE_REGISTERING = 1;
+
+    public static int SIP_REGSTATE_REGISTERED = 2;
+
+    public static int SIP_REGSTATE_UNREGISTERING = 3;
+
+    public static int SIP_REGSTATE_AUTHORIZING = 4;
+
+    public static int SIP_REGSTATE_UNAUTHORIZED = 5;
+
+    public static int SIP_REGSTATE_UNAVAILABLE = 6;
+
+    public static final int SIP_CALLSTATE_IDLE = 0;
+
+    public static final int SIP_CALLSTATE_INVITING = 1;
+
+    public static final int SIP_CALLSTATE_OFFERRED = 2;
+
+    public static final int SIP_CALLSTATE_PROCEEDING = 3;
+
+    public static final int SIP_CALLSTATE_PROGRESSING = 4;
+
+    public static final int SIP_CALLSTATE_ACCEPTED = 5;
+
+    public static final int SIP_CALLSTATE_REMOTEACCEPTED = 6;
+
+    public static final int SIP_CALLSTATE_CONNECTED = 7;
+
+    public static final int SIP_CALLSTATE_DISCONNECTING = 8;
+
+    public static final int SIP_CALLSTATE_TERMINATING = 9;
+
+    public static final int SIP_CALLSTATE_UNAUTHORIZED = 10;
+
+    public static final int SIP_CALLSTATE_CANCELLING = 11;
+
+    public static final int SIP_CALLSTATE_CANCELLED = 12;
+
+    public static final int SIP_CALLSTATE_RECANCELLING = 13;
+
+    public static final int SIP_CALLSTATE_CANCELREMOTEACCEPTED = 14;
+
+    public static final int SIP_CALLSTATE_REJECTED = 15;
+
+    public static final int SIP_CALLSTATE_REDIRECTED = 16;
+
+    public static final int SIP_CALLSTATE_UPDATING = 20;
+
+    public static final int SIP_CALLSTATE_UPDATEPROCEEDING = 21;
+
+    public static final int SIP_CALLSTATE_UPDATEPROGRESSING = 22;
+
+    public static final int SIP_CALLSTATE_UPDATEOFFERRED = 23;
+
+    public static final int SIP_CALLSTATE_UPDATEACCEPTED = 24;
+
+    public static final int SIP_CALLSTATE_UPDATEREJECTED = 25;
+
+    public static final int SIP_CALLSTATE_UPDATEREMOTEACCEPTED = 26;
+
+    public static final int SIP_CALLSTATE_UPDATEREMOTEREJECTED = 27;
+
+    public static final int SIP_CALLSTATE_UPDATEUNAUTHORIZED = 28;
+
+    public static final int SIP_CALLSTATE_UPDATEREDIRECTED = 29;
+
+    public static int SIP_CALLMODE_NONE = 0;
+
+    public static int SIP_CALLMODE_BASIC = 1;
+
+    public static int SIP_CALLMODE_HOLD = 2;
+
+    public static int SIP_SERVICEMODE_BASIC = 0;
+
+    public static int SIP_SERVICEMODE_CONFERENCE = 1;
+
+    public static int SIP_CALLDIRECTION_NONE = 0;
+
+    public static int SIP_CALLDIRECTION_IN = 1;
+
+    public static int SIP_CALLDIRECTION_OUT = 2;
+
+    public static int SIP_MEDIATYPE_NONE = 0;
+
+    public static int SIP_MEDIATYPE_AUDIO = 1;
+
+    public static int SIP_MEDIATYPE_VIDEO = 2;
+
+    public static int SIP_CODEC_NONE = -1;
+
+    public static int SIP_CODEC_G711U = 0;
+
+    public static int SIP_CODEC_G711A = 8;
+
+    public static int SIP_CODEC_G7231 = 4;
+
+    public static int SIP_CODEC_G729 = 18;
+
+    public static int SIP_CODEC_H263 = 34;
+
+    public static int SIP_CODEC_H264 = 98;
+
+    public static int PRIMARY_CODEC_AUDIO = SIP_CODEC_G711U;
+
+    public static int PRIMARY_CODEC_VIDEO = SIP_CODEC_H263;
+
+    public static int SIP_DTMFINFO_DTMFRELAY = 0;
+
+    public static int SIP_DTMFINFO_DTMF = 1;
+
+    public static int SIP_SEQUENCE_INVITE = 1;
+
+    public static int SIP_SEQUENCE_REGISTER = 1;
+
+    public static int SIP_MEDIA_INITPORT = 3000;
+
+    public static int SIP_MEDIA_PORTS = 5;
+
+    public static int SIP_MEDIAFLOW_NONE = 0;
+
+    public static int SIP_MEDIAFLOW_SENDRECV = 1;
+
+    public static int SIP_MEDIAFLOW_SENDONLY = 2;
+
+    public static int SIP_MEDIAFLOW_RECVONLY = 3;
+
+    public static int RTP_AUDIO_SIZE = 1024;
+
+    public static int RTP_VIDEO_SIZE = 30000;
+
+    public static boolean[] SIP_MEDIA_PORTFLAG = new boolean[SIP_MEDIA_PORTS];
+
+    public static int CS_TIMEOUT_TI = 3;
+
+    public static int CS_TIMEOUT_T0 = 15;
+
+    public static int CS_TIMEOUT_T00 = 10;
+
+    public static int CS_TIMEOUT_T000 = 5;
+
+    public static int CS_TIMEOUT_T1 = 30;
+
+    public static int CS_TIMEOUT_T2 = 120;
+
+    public static int CS_TIMEOUT_T3 = 7;
+
+    public static int CS_TIMEOUT_T4 = 7200;
+
+    public static int CS_TIMEOUT_T5 = 7;
+
+    public static int CS_TIMEOUT_T6 = 0;
+
+    public static int CS_TIMEOUT_T7 = 30;
+
+    public static int CS_TIMEOUT_T8 = 7;
+
+    public static int CS_TIMEOUT_T80 = 2;
+
+    public static int CS_TIMEOUT_RESPONSE = 1;
+
+    public static int NETWORKIF_CHECK_TIME = 5;
+
+    public static int TEARDOWN_CODE_NORMAL = 0;
+
+    public static int TEARDOWN_CODE_EEREJECT = 1;
+
+    public static int TEARDOWN_CODE_ERREJECT = 2;
+
+    public static int TEARDOWN_CODE_NOTFOUND = 3;
+
+    public static int TEARDOWN_CODE_ERROR = 4;
+
+    public static int SIP_NETIF_UNAVAILABLE = 0;
+
+    public static int SIP_NETIF_AVAILABLE = 1;
+
+    public static int SIP_NETIF_UNREACHABLE = 2;
+
+    public static int REPEAT_SENDCOUNT = 3;
+
+    public static int SIP_MAXMESSAGE_SIZE = 2500;
+
+    public static boolean SIP_MESSAGE_DEBUG = false;
+
+    public static boolean SIP_CALLHANDLE_DEBUG = false;
+
+    public static Date bootTime = new Date();
+
+    public static int exceptionCountAtCurrentCall = 0;
+
+    public static boolean ventureCall = true;
+
+    public static boolean bLimitedUse = false;
+
+    public static int BACKGROUNDIDLE_MAX_SECONDS = 28800;
+
+    public static int networkStatus = SIP_NETIF_UNAVAILABLE;
+
+    public static String generalPhoneNumber = "";
+
+    public static String hwModelName = "";
+
+    public static String hwId = "";
+
+    public static String firmVersion = "";
+
+    public static String hwImsi = "";
+
+    public static String hwImei = "";
+
+    public static String gcmRegistId = "";
+
+    public static boolean bGCMRegistSend = false;
+
+    public static String ANDROID_API_KEY = "AIzaSyDZcNyOPs5iTQ9kGZaF56Ngf4eCQDzMEl0";
+
+    public static boolean isInternetWiMax = false;
+
+    public static boolean isInternetWiFi = false;
+
+    public static boolean isInternetMobile = false;
+
+    public static String localSdpIp = "0.0.0.0";
+
+    public static boolean usePrivateWiMax = true;
+
+    public static boolean bShutdownApplication = false;
+
+    public static boolean bOuttraffic = false;
+
+    public static boolean bIntraffic = false;
+
+    public static String macAddress = "";
+
+    public static boolean bTtsservice = false;
+
+    public static boolean bSupportTts = false;
+
+    public static int WIFI_CALL_SIGNAL_MIN = 3;
+
+    public static Date networkInfoCheckTime = new Date();
+
+    public static int WIFI_SIGNAL_VALUE = 0;
+
+    public static String mobileLanguage = "ko";
+
+    public static boolean bActive = false;
+
+    public static boolean bVibrator = true;
+
+    public static boolean bVibrating = false;
+
+    public static int iVibrator = 0;
+
+    public static GetIpDns ipdns = new GetIpDns();
+
+    public static boolean bNetworkActive = false;
+
+    public static int antenaOnStep = 0;
+
+    public static boolean bProximityOn = false;
+
+    public static int localPort = SIP_LOCAL_PORT;
+
+    public static String strLocalip = null;
+
+    public static boolean bBackgroundRunning = false;
+
+    public static boolean bGeneralPhoneDetected = false;
+
+    public static stackKey stackkey = new stackKey();
+
+    public static Date backgroundEnteredTime = new Date();
+
+    public static boolean bdialContextActive = false;
+
+    public static UserDial userDial = new UserDial();
+
+    public static int SIPCTRL_INTERVAL = 40;
+
+    public static boolean bVideocommunication = true;
+
+    public static boolean bDirectCall = true;
+
+    protected static boolean bStackLicensed = false;
+
+    public static boolean bUseSendTimer = false;
+
+    public static boolean bUseCtrlTimer = false;
+
+    public static int getCSeqMethod(String s) {
+        int iMethodType = SIP_METHODTYPE_NONE;
+        int iS = s.indexOf("CSeq: ");
+        int iE = 0;
+        if (iS >= 0)
+            iE = s.indexOf(SIP_LINE_END, iS);
+        if (iE <= 0)
+            return iMethodType;
+        String strCSEQ = s.substring(iS, iE);
+        StringTokenizer tokenArray = new StringTokenizer(strCSEQ, " ", true);
+        int tokenCount = 0;
+        while (tokenArray.hasMoreTokens()) {
+            String token = tokenArray.nextToken();
+            if (token.length() > 0 && token.compareTo(" ") != 0) {
+                tokenCount++;
+                if (tokenCount == 3) {
+                    if (token.compareTo("REGISTER") == 0) {
+                        iMethodType = SIP_METHODTYPE_REGISTER;
+                        break;
+                    }
+                    if (token.compareTo("INVITE") == 0) {
+                        iMethodType = SIP_METHODTYPE_INVITE;
+                        break;
+                    }
+                    if (token.compareTo("CANCEL") == 0) {
+                        iMethodType = SIP_METHODTYPE_CANCEL;
+                        break;
+                    }
+                    if (token.compareTo("BYE") == 0) {
+                        iMethodType = SIP_METHODTYPE_BYE;
+                        break;
+                    }
+                    if (token.compareTo("INFO") == 0) {
+                        iMethodType = SIP_METHODTYPE_INFO;
+                        break;
+                    }
+                    if (token.compareTo("OPTIONS") == 0) {
+                        iMethodType = SIP_METHODTYPE_OPTIONS;
+                        break;
+                    }
+                    if (token.compareTo("ACK") == 0) {
+                        iMethodType = SIP_METHODTYPE_ACK;
+                        break;
+                    }
+                    if (token.compareTo("REFER") == 0) {
+                        iMethodType = SIP_METHODTYPE_REFER;
+                        break;
+                    }
+                    if (token.compareTo("NOTIFY") == 0) {
+                        iMethodType = SIP_METHODTYPE_NOTIFY;
+                        break;
+                    }
+                    if (token.compareTo("MESSAGE") == 0) {
+                        iMethodType = SIP_METHODTYPE_MESSAGE;
+                        break;
+                    }
+                    if (token.compareTo("SUBSCRIBE") == 0) {
+                        iMethodType = SIP_METHODTYPE_SUBSCRIBE;
+                        break;
+                    }
+                    if (token.compareTo("PRACK") == 0)
+                        iMethodType = SIP_METHODTYPE_PRACK;
+                    break;
+                }
+            }
+        }
+        return iMethodType;
+    }
+
+    public static int getRequestlineMethod(String str) {
+        int iMethodType = SIP_METHODTYPE_NONE;
+        if (str.startsWith("INVITE") && str.endsWith("SIP/2.0\r")) {
+            iMethodType = SIP_METHODTYPE_INVITE;
+        } else if (str.startsWith("BYE") && str.endsWith("SIP/2.0\r")) {
+            iMethodType = SIP_METHODTYPE_BYE;
+        } else if (str.startsWith("ACK") && str.endsWith("SIP/2.0\r")) {
+            iMethodType = SIP_METHODTYPE_ACK;
+        } else if (str.startsWith("CANCEL") && str.endsWith("SIP/2.0\r")) {
+            iMethodType = SIP_METHODTYPE_CANCEL;
+        } else if (str.startsWith("OPTIONS") && str.endsWith("SIP/2.0\r")) {
+            iMethodType = SIP_METHODTYPE_OPTIONS;
+        } else if (str.startsWith("INFO") && str.endsWith("SIP/2.0\r")) {
+            iMethodType = SIP_METHODTYPE_INFO;
+        } else if (str.startsWith("PRACK") && str.endsWith("SIP/2.0\r")) {
+            iMethodType = SIP_METHODTYPE_PRACK;
+        } else if (str.startsWith("MESSAGE") && str.endsWith("SIP/2.0\r")) {
+            iMethodType = SIP_METHODTYPE_MESSAGE;
+        } else if (str.startsWith("SUBSCRIBE") && str.endsWith("SIP/2.0\r")) {
+            iMethodType = SIP_METHODTYPE_SUBSCRIBE;
+        } else if (str.startsWith("REFER") && str.endsWith("SIP/2.0\r")) {
+            iMethodType = SIP_METHODTYPE_REFER;
+        } else if (str.startsWith("NOTIFY") && str.endsWith("SIP/2.0\r")) {
+            iMethodType = SIP_METHODTYPE_NOTIFY;
+        } else if (str.startsWith("REGISTER") && str.endsWith("SIP/2.0\r")) {
+            iMethodType = SIP_METHODTYPE_REGISTER;
+        } else if (str.startsWith("SIP/2.0") && str.endsWith("\r")) {
+            iMethodType = SIP_METHODTYPE_RESPONSE;
+        }
+        return iMethodType;
+    }
+
+    public static void setLicense(String strLicense) {
+        if (bLimitedUse) {
+            Date currentDate = new Date();
+            int month = currentDate.getMonth() + 1;
+            int day = currentDate.getDate();
+            int year = currentDate.getYear() + 1900;
+            if (year != 2014 || month > 12) {
+                System.out.println("사용기간 종료되었습니다.");
+                        bStackLicensed = false;
+                System.exit(0);
+            }
+        }
+        String license = "주식회사아이콘트롤스 200701243005451";
+        if (strLicense.compareTo(license) == 0) {
+            bStackLicensed = true;
+        } else {
+            System.out.println("SIP 라이슨스가 맞지 않습니다.");
+                    bStackLicensed = false;
+        }
+        System.out.println(
+                "이 스택은 아이콘트롤스 홈네트워크용입니다.");
+    }
+
+    public static String getResponseDescription(int code) {
+        switch (code) {
+            case 100:
+                return "Trying";
+            case 180:
+                return "Ringing";
+            case 181:
+                return "Call Is Being Forwarded";
+            case 182:
+                return "Call Queued";
+            case 183:
+                return "Session Progress";
+            case 200:
+                return "OK";
+            case 300:
+                return "Multiple Choices";
+            case 301:
+                return "Moved Permanently";
+            case 302:
+                return "Moved Temporarily";
+            case 305:
+                return "Use Proxy";
+            case 380:
+                return "Alternative Service";
+            case 400:
+                return "Bad Request";
+            case 401:
+                return "Unauthorized";
+            case 402:
+                return "Payment Required";
+            case 403:
+                return "Forbidden";
+            case 404:
+                return "Not Found";
+            case 405:
+                return "Method Not Allowed";
+            case 406:
+                return "Not Acceptable";
+            case 407:
+                return "Proxy Authentication Required";
+            case 408:
+                return "Request Timeout";
+            case 409:
+                return "Conflict";
+            case 410:
+                return "Gone";
+            case 411:
+                return "Length Required";
+            case 413:
+                return "Request Entity Too Large";
+            case 414:
+                return "Request-URI Too Long";
+            case 415:
+                return "Unsupported Media Type";
+            case 420:
+                return "Bad Extension";
+            case 421:
+                return "Extension Required";
+            case 423:
+                return "Interval Too Brief";
+            case 480:
+                return "Temporarily Unavailable";
+            case 481:
+                return "Call Leg Does Not Exist";
+            case 482:
+                return "Loop Detected";
+            case 483:
+                return "Two Many Hops";
+            case 484:
+                return "Address Incomplete";
+            case 485:
+                return "Ambiguous";
+            case 486:
+                return "Busy Here";
+            case 487:
+                return "Request Canceled";
+            case 488:
+                return "Not Acceptable Here";
+            case 500:
+                return "Server Internal Error";
+            case 501:
+                return "Not Implemented";
+            case 502:
+                return "Bad Gateway";
+            case 503:
+                return "Service Unavailable";
+            case 504:
+                return "Gateway Timeout";
+            case 505:
+                return "Version Not Supported";
+            case 600:
+                return "Busy Everywhere";
+            case 603:
+                return "Decline";
+            case 604:
+                return "Does Not Exist Anywhere";
+            case 606:
+                return "Not Acceptable";
+        }
+        return "";
+    }
+
+    public static String BSSMD5Get(String data) {
+        if (data == null || data.length() <= 0)
+            return null;
+        try {
+            SIPmd5 md = SIPmd5.getInstance();
+            return md.hashData(data.getBytes());
+        } catch (NoSuchAlgorithmException e) {
+            e.printStackTrace(System.out);
+            exceptionCountAtCurrentCall++;
+            return null;
+        }
+    }
+
+    public static String getViaBranch() {
+        Date today = new Date();
+        return "z9hG4bK-" + today.getTime() + "-" + ((int)today.getTime() % 7);
+    }
+
+    public static String newTag(String prefix) {
+        Date today = new Date();
+        return String.valueOf(prefix) + today.getTime() + "-" + today.hashCode();
+    }
+
+    public static String newTag() {
+        Date today = new Date();
+        return String.valueOf(today.getTime()) + "." + today.hashCode();
+    }
+
+    public static int getFreeAudioRtpPort() {
+        for (int i = 0; i < SIP_MEDIA_PORTS; i++) {
+            if (!SIP_MEDIA_PORTFLAG[i]) {
+                SIP_MEDIA_PORTFLAG[i] = true;
+                return SIP_MEDIA_INITPORT + i * 2;
+            }
+        }
+        return 0;
+    }
+
+    public static boolean freeAudioRtpPort(int port) {
+        int index = (port - SIP_MEDIA_INITPORT) / 2;
+        if (index >= 0 && index < SIP_MEDIA_PORTS) {
+            SIP_MEDIA_PORTFLAG[index] = false;
+            return true;
+        }
+        return false;
+    }
+
+    public static void printAudioRtpPortInfo() {
+        System.out.print(">>>> RTP PORT STATUS  ");
+        for (int i = 0; i < SIP_MEDIA_PORTS; i++)
+            System.out.print("  " + SIP_MEDIA_PORTFLAG[i]);
+        System.out.println("  ");
+    }
+
+    public static String getIPV4(String host) {
+        if (host == null || host.length() == 0)
+            return null;
+        String ip = null;
+        try {
+            InetAddress ia = InetAddress.getByName(host);
+            byte[] address = ia.getAddress();
+            if (address.length == 4) {
+                int unsignedByte1 = (address[0] < 0) ? (address[0] + 256) : address[0];
+                int unsignedByte2 = (address[1] < 0) ? (address[1] + 256) : address[1];
+                int unsignedByte3 = (address[2] < 0) ? (address[2] + 256) : address[2];
+                int unsignedByte4 = (address[3] < 0) ? (address[3] + 256) : address[3];
+                ip = String.valueOf(unsignedByte1) + "." + unsignedByte2 + "." + unsignedByte3 + "." + unsignedByte4;
+            }
+        } catch (UnknownHostException uhe) {
+            System.err.println(uhe);
+            exceptionCountAtCurrentCall++;
+        } catch (Exception e) {
+            System.err.println(e);
+        }
+        return ip;
+    }
+
+    public static boolean isPrivateIp(String ip) {
+        if (ip == null || ip.length() < 7)
+            return false;
+        boolean bPrivate = false;
+        StringTokenizer st = new StringTokenizer(ip, ".", true);
+        int tokenCount = 0;
+        String token = null;
+        int ipdigit_0 = 0;
+        int ipdigit_1 = 0;
+        while (st.hasMoreTokens()) {
+            token = st.nextToken().trim();
+            if (token != null && token.length() > 0 &&
+                    token.length() <= 3 &&
+                    token.compareTo(".") != 0) {
+                if (tokenCount == 0) {
+                    ipdigit_0 = Integer.parseInt(token.trim());
+                } else if (tokenCount == 1) {
+                    ipdigit_1 = Integer.parseInt(token.trim());
+                }
+                tokenCount++;
+            }
+        }
+        if (tokenCount == 4)
+            bPrivate = !(ipdigit_0 != 10 && (
+                    ipdigit_0 != 172 || ipdigit_1 < 16 || ipdigit_1 > 31) && (
+                    ipdigit_0 != 192 || ipdigit_1 != 168));
+        return bPrivate;
+    }
+
+    public static boolean getLicensed() {
+        return bStackLicensed;
+    }
+}

+ 124 - 0
WallPadCall/src/main/java/bssoft/stack/sip/SIPVIAHeader.java

@@ -0,0 +1,124 @@
+package bssoft.stack.sip;
+
+import java.util.StringTokenizer;
+
+public class SIPVIAHeader {
+    public String header = null;
+
+    public String headerValue = null;
+
+    public String branch = null;
+
+    public String received = null;
+
+    public int rport = -1;
+
+    public String ip = null;
+
+    public int port = 0;
+
+    public String tag = null;
+
+    public boolean rportService = false;
+
+    public boolean flag = false;
+
+    public SIPVIAHeader(String message) {
+        if (message != null && message.length() > 0) {
+            this.rport = 0;
+            this.received = null;
+            int iS = message.indexOf("Via: ");
+            int iE = 0;
+            if (iS < 0) {
+                iS = message.indexOf(String.valueOf(SIPStack.SIP_LINE_END) + "v: ");
+                if (iS >= 0)
+                    iS += 2;
+            }
+            if (iS >= 0) {
+                iE = message.indexOf(SIPStack.SIP_LINE_END, iS);
+                if (iE > 0) {
+                    this.header = message.substring(iS, iE);
+                    if (this.header.startsWith("Via: ")) {
+                        this.headerValue = this.header.substring(5);
+                    } else if (this.header.startsWith("v: ")) {
+                        this.headerValue = this.header.substring(3);
+                    }
+                }
+            }
+            if (this.headerValue != null && this.headerValue.length() > 0) {
+                StringTokenizer st = new StringTokenizer(this.headerValue, ";", true);
+                int tokenCount = 0;
+                String token = null;
+                while (st.hasMoreTokens()) {
+                    token = st.nextToken().trim();
+                    if (token != null && token.length() > 0 && token.compareTo(";") != 0) {
+                        tokenCount++;
+                        if (tokenCount == 1 && token.startsWith("SIP/")) {
+                            StringTokenizer tokenArray = new StringTokenizer(token, " ", true);
+                            int fieldCount = 0;
+                            while (tokenArray.hasMoreTokens()) {
+                                String field = tokenArray.nextToken().trim();
+                                if (field != null && field.length() > 0 && field.compareTo(" ") != 0) {
+                                    fieldCount++;
+                                    if (fieldCount == 2) {
+                                        iS = field.indexOf(":");
+                                        if (iS > 0) {
+                                            this.port = Integer.parseInt(field.substring(iS + 1));
+                                            this.ip = field.substring(0, iS);
+                                            continue;
+                                        }
+                                        this.port = 5060;
+                                        this.ip = field;
+                                    }
+                                }
+                            }
+                            continue;
+                        }
+                        if (tokenCount != 1 && token.startsWith("branch=")) {
+                            this.branch = token.substring(7);
+                            continue;
+                        }
+                        if (tokenCount != 1 && token.compareTo("rport") == 0) {
+                            this.rportService = true;
+                            continue;
+                        }
+                        if (tokenCount != 1 && token.startsWith("rport=")) {
+                            this.rportService = true;
+                            this.rport = Integer.parseInt(token.substring(6).trim());
+                            continue;
+                        }
+                        if (tokenCount != 1 && token.startsWith("received=")) {
+                            this.rportService = true;
+                            this.received = token.substring(9).trim();
+                        }
+                    }
+                }
+                this.flag = true;
+            }
+        }
+    }
+
+    public String getReceived() {
+        return this.received;
+    }
+
+    public int getRport() {
+        return this.rport;
+    }
+
+    public String getAddress() {
+        return String.valueOf(this.ip) + ":" + this.port;
+    }
+
+    public String getIp() {
+        return this.ip;
+    }
+
+    public int getPort() {
+        return this.port;
+    }
+
+    public String getBranch() {
+        return this.branch;
+    }
+}

+ 38 - 0
WallPadCall/src/main/java/bssoft/stack/sip/SIPmd5.java

@@ -0,0 +1,38 @@
+package bssoft.stack.sip;
+
+import java.security.MessageDigest;
+import java.security.NoSuchAlgorithmException;
+
+public class SIPmd5 {
+    public MessageDigest md = null;
+
+    public static SIPmd5 md5 = null;
+
+    public SIPmd5() throws NoSuchAlgorithmException {
+        this.md = MessageDigest.getInstance("MD5");
+    }
+
+    public static SIPmd5 getInstance() throws NoSuchAlgorithmException {
+        if (md5 == null)
+            md5 = new SIPmd5();
+        return md5;
+    }
+
+    public String hashData(byte[] dataToHash) {
+        return hexStringFromBytes(calculateHash(dataToHash));
+    }
+
+    public byte[] calculateHash(byte[] dataToHash) {
+        this.md.update(dataToHash, 0, dataToHash.length);
+        return this.md.digest();
+    }
+
+    public String hexStringFromBytes(byte[] b) {
+        StringBuffer sb = new StringBuffer();
+        for (int i = 0; i < b.length; i++) {
+            String md5Char = String.format("%02x", new Object[] { Integer.valueOf(0xFF & (char)b[i]) });
+            sb.append(md5Char);
+        }
+        return sb.toString();
+    }
+}

+ 294 - 0
WallPadCall/src/main/java/bssoft/stack/sip/UPDATEHeaders.java

@@ -0,0 +1,294 @@
+package bssoft.stack.sip;
+
+import java.util.Date;
+
+public class UPDATEHeaders {
+    public String commandLine = null;
+
+    public String viaH = null;
+
+    public StringBuffer viaArray = null;
+
+    public String routeH = null;
+
+    public StringBuffer routeArray = null;
+
+    public String recordrouteH = null;
+
+    public StringBuffer recordrouteArray = null;
+
+    public String maxforwardH = null;
+
+    public String contactH = null;
+
+    public String toH = null;
+
+    public String fromH = null;
+
+    public String callidH = null;
+
+    public String cseqH = null;
+
+    public String expiresH = null;
+
+    public String allowH = null;
+
+    public String useragentH = null;
+
+    public String remoteuseragentH = null;
+
+    public String contentlengthH = null;
+
+    public String contenttypeH = null;
+
+    public String authorizationINVITEH = null;
+
+    public String authorizationCANCELH = null;
+
+    public String authorizationBYEH = null;
+
+    public String authorizationACKH = null;
+
+    public String passertedidentityH = null;
+
+    public String serverIp = null;
+
+    public int serverPort = 5060;
+
+    public String serverDomain = null;
+
+    public String remoteIp = null;
+
+    public int remotePort = 5060;
+
+    public String remoteContactIp = null;
+
+    public int remoteContactPort = 5060;
+
+    public String remoteContactUri = null;
+
+    public String localIp = null;
+
+    public int localPort = 5060;
+
+    public String id = null;
+
+    public String cid = null;
+
+    public String authid = null;
+
+    public String authpassword = null;
+
+    public String fromTag = null;
+
+    public String toTag = null;
+
+    public String fromHeaderValue = null;
+
+    public String toHeaderValue = null;
+
+    public String callId = null;
+
+    public String dnis = null;
+
+    public String viaBranch = null;
+
+    public int CSEQ_NUMBER = SIPStack.SIP_SEQUENCE_INVITE;
+
+    public int INVITE_CSEQ = 0;
+
+    public int CANCEL_CSEQ = 0;
+
+    public int ACK_CSEQ = 0;
+
+    public int BYE_CSEQ = 0;
+
+    public int callDirection = SIPStack.SIP_CALLDIRECTION_NONE;
+
+    public int callState = 0;
+
+    public int callMode = SIPStack.SIP_CALLMODE_NONE;
+
+    public Date callTime_TI = null;
+
+    public Date callTime_T0 = null;
+
+    public Date callTime_T00 = null;
+
+    public int invitingTimes = 0;
+
+    public Date callTime_T1 = null;
+
+    public Date callTime_T2 = null;
+
+    public Date callTime_T3 = null;
+
+    public Date callTime_T4 = null;
+
+    public Date callTime_T40 = null;
+
+    public Date callTime_T5 = null;
+
+    public Date callTime_T6 = null;
+
+    public Date callTime_T7 = null;
+
+    public Date callTime_T8 = null;
+
+    public Date callTime_T9 = null;
+
+    public int expiresTI = 0;
+
+    public int expiresT0 = 0;
+
+    public int expiresT00 = 0;
+
+    public int expiresT1 = 0;
+
+    public int expiresT2 = 0;
+
+    public int expiresT3 = 0;
+
+    public int expiresT4 = 0;
+
+    public int expiresT5 = 0;
+
+    public int expiresT6 = 0;
+
+    public int expiresT7 = 0;
+
+    public int expiresT8 = 0;
+
+    public int expiresT9 = 0;
+
+    public SIPSdp sdp = null;
+
+    public SIPSdp remoteSdp = null;
+
+    public String message = null;
+
+    public boolean flag;
+
+    public UPDATEHeaders() {
+        if (SIPStack.SIP_CALLHANDLE_DEBUG)
+            System.out.println("call handle created.");
+        this.CSEQ_NUMBER = SIPStack.SIP_SEQUENCE_INVITE;
+        this.callState = 0;
+        this.callMode = SIPStack.SIP_CALLMODE_BASIC;
+        this.callTime_TI = new Date();
+        this.callTime_T0 = new Date();
+        this.callTime_T00 = new Date();
+        this.invitingTimes = 0;
+        this.callTime_T1 = new Date();
+        this.callTime_T2 = new Date();
+        this.callTime_T3 = new Date();
+        this.callTime_T4 = new Date();
+        this.callTime_T40 = new Date();
+        this.callTime_T5 = new Date();
+        this.callTime_T6 = new Date();
+        this.callTime_T7 = new Date();
+        this.callTime_T8 = new Date();
+        this.callTime_T9 = new Date();
+        this.expiresTI = 0;
+        this.expiresT0 = 0;
+        this.expiresT00 = 0;
+        this.expiresT1 = 0;
+        this.expiresT2 = 0;
+        this.expiresT3 = 0;
+        this.expiresT4 = 0;
+        this.expiresT5 = 0;
+        this.expiresT6 = 0;
+        this.expiresT7 = 0;
+        this.expiresT8 = 0;
+        this.expiresT9 = 0;
+        this.sdp = null;
+        this.remoteSdp = null;
+        this.flag = false;
+    }
+
+    public void reset() {
+        this.commandLine = null;
+        this.viaH = null;
+        this.viaArray = null;
+        this.routeH = null;
+        this.routeArray = null;
+        this.recordrouteH = null;
+        this.recordrouteArray = null;
+        this.maxforwardH = null;
+        this.contactH = null;
+        this.toH = null;
+        this.fromH = null;
+        this.callidH = null;
+        this.cseqH = null;
+        this.expiresH = null;
+        this.allowH = null;
+        this.useragentH = null;
+        this.remoteuseragentH = null;
+        this.contentlengthH = null;
+        this.contenttypeH = null;
+        this.authorizationINVITEH = null;
+        this.authorizationCANCELH = null;
+        this.authorizationBYEH = null;
+        this.authorizationACKH = null;
+        this.passertedidentityH = null;
+        this.serverIp = null;
+        this.serverPort = 5060;
+        this.serverDomain = null;
+        this.remoteIp = null;
+        this.remotePort = 5060;
+        this.remoteContactIp = null;
+        this.remoteContactPort = 5060;
+        this.remoteContactUri = null;
+        this.localIp = null;
+        this.localPort = 5060;
+        this.id = null;
+        this.cid = null;
+        this.authid = null;
+        this.authpassword = null;
+        this.fromTag = null;
+        this.toTag = null;
+        this.fromHeaderValue = null;
+        this.toHeaderValue = null;
+        this.callId = null;
+        this.dnis = null;
+        this.viaBranch = null;
+        this.CSEQ_NUMBER = SIPStack.SIP_SEQUENCE_INVITE;
+        this.INVITE_CSEQ = 0;
+        this.CANCEL_CSEQ = 0;
+        this.ACK_CSEQ = 0;
+        this.BYE_CSEQ = 0;
+        this.callDirection = SIPStack.SIP_CALLDIRECTION_NONE;
+        this.callState = 0;
+        this.callMode = SIPStack.SIP_CALLMODE_NONE;
+        this.callTime_TI = null;
+        this.callTime_T0 = null;
+        this.callTime_T00 = null;
+        this.invitingTimes = 0;
+        this.callTime_T1 = null;
+        this.callTime_T2 = null;
+        this.callTime_T3 = null;
+        this.callTime_T4 = null;
+        this.callTime_T40 = null;
+        this.callTime_T5 = null;
+        this.callTime_T6 = null;
+        this.callTime_T7 = null;
+        this.callTime_T8 = null;
+        this.callTime_T9 = null;
+        this.expiresTI = 0;
+        this.expiresT0 = 0;
+        this.expiresT00 = 0;
+        this.expiresT1 = 0;
+        this.expiresT2 = 0;
+        this.expiresT3 = 0;
+        this.expiresT4 = 0;
+        this.expiresT5 = 0;
+        this.expiresT6 = 0;
+        this.expiresT7 = 0;
+        this.expiresT8 = 0;
+        this.expiresT9 = 0;
+        this.sdp = null;
+        this.remoteSdp = null;
+        this.message = null;
+        this.flag = false;
+    }
+}

+ 11 - 0
WallPadCall/src/main/java/bssoft/stack/sip/UserDial.java

@@ -0,0 +1,11 @@
+package bssoft.stack.sip;
+
+public class UserDial {
+    public String dial = "";
+
+    public String dong = "";
+
+    public String ho = "";
+
+    public String latestDial = "";
+}

+ 87 - 0
WallPadCall/src/main/java/bssoft/stack/sip/stackKey.java

@@ -0,0 +1,87 @@
+package bssoft.stack.sip;
+
+public class stackKey {
+    public String KEY_BSS_SMARTINFO;
+
+    public String KEY_BSS_ID;
+
+    public String KEY_BSS_AUTHID;
+
+    public String KEY_BSS_PASSWORD;
+
+    public String KEY_BSS_CID;
+
+    public String KEY_BSS_SERVERIP;
+
+    public String KEY_BSS_SERVERDOMAIN;
+
+    public String KEY_BSS_SERVERPORT;
+
+    public String KEY_BSS_PMPSET;
+
+    public String KEY_BSS_IMSI;
+
+    public String KEY_BSS_GENERALPHONE;
+
+    public String KEY_BSS_WEBID;
+
+    public String KEY_BSS_WEBPWD;
+
+    public String KEY_BSS_LATESTDIAL;
+
+    public String KEY_BSS_FORWARD;
+
+    public String strId = "";
+
+    public String strCid = "";
+
+    public String strAuthid = "";
+
+    public String strAuthpassword = "";
+
+    public String strServerHost = "";
+
+    public String strServerDomain = "";
+
+    public String strImsi = "";
+
+    public String strGeneralPhone = "";
+
+    public String strWebId = "";
+
+    public String strWebPwd = "";
+
+    public int serverPort = 5060;
+
+    public String strForward = "";
+
+    public stackKey() {
+        this.KEY_BSS_SMARTINFO = "bss_smartinfo";
+        this.KEY_BSS_ID = "bss_id";
+        this.KEY_BSS_AUTHID = "bss_authid";
+        this.KEY_BSS_PASSWORD = "bss_password";
+        this.KEY_BSS_CID = "bss_cid";
+        this.KEY_BSS_SERVERIP = "bss_serverip";
+        this.KEY_BSS_SERVERDOMAIN = "bss_serverdomain";
+        this.KEY_BSS_SERVERPORT = "bss_serverport";
+        this.KEY_BSS_PMPSET = "bss_pmpset";
+        this.KEY_BSS_IMSI = "bss_imsi";
+        this.KEY_BSS_GENERALPHONE = "bss_generalphone";
+        this.KEY_BSS_WEBID = "bss_webid";
+        this.KEY_BSS_WEBPWD = "bss_webpwd";
+        this.KEY_BSS_LATESTDIAL = "bss_latestdial";
+        this.KEY_BSS_FORWARD = "bss_forward";
+        this.strId = "";
+        this.strCid = "";
+        this.strAuthid = "";
+        this.strAuthpassword = "";
+        this.strServerHost = "";
+        this.strServerDomain = "";
+        this.strImsi = "";
+        this.strGeneralPhone = "";
+        this.strWebId = "";
+        this.strWebPwd = "";
+        this.serverPort = 5060;
+        this.strForward = "";
+    }
+}

+ 228 - 0
WallPadCall/src/main/java/bssoft/stack/sip/videoEnc.java

@@ -0,0 +1,228 @@
+package bssoft.stack.sip;
+
+public class videoEnc {
+    public boolean bReceiveRunning = false;
+
+    public byte[] buffer = null;
+
+    public byte[] rtpVideoBuffer = null;
+
+    public byte[] data = null;
+
+    public int RTP_VIDEO_SIZE = 50000;
+
+    public int RTPversion = 0;
+
+    public int RTPpadding = 0;
+
+    public int RTPextension = 0;
+
+    public int RTPcsrc = 0;
+
+    public int RTPmark = 0;
+
+    public int RTPpayload = 0;
+
+    public int RTPsequence = 0;
+
+    public int RTPtimestamp = 0;
+
+    public int RTPssrc = 0;
+
+    public boolean bService = false;
+
+    public String remoteIp = "127.0.0.1";
+
+    public int remotePort = 3002;
+
+    public byte[] rtpfieldBytes = null;
+
+    public boolean bIframeset = false;
+
+    public boolean bIframedoubleset = false;
+
+    public boolean bView = false;
+
+    public int PARSEversion = 0;
+
+    public int PARSEpadding = 0;
+
+    public int PARSEextension = 0;
+
+    public int PARSEcsrc = 0;
+
+    public int PARSEmark = 0;
+
+    public int PARSEpayload = 0;
+
+    public int PARSEsequence = 0;
+
+    public int PARSEtimestamp = 0;
+
+    public int PARSEssrc = 0;
+
+    public int PARSEview = 0;
+
+    public videoEnc() {
+        if (!SIPStack.bStackLicensed) {
+            System.out.println("라이슨스키를 설정하세요.");
+                    System.exit(0);
+        }
+        this.buffer = new byte[this.RTP_VIDEO_SIZE];
+        this.rtpVideoBuffer = new byte[this.RTP_VIDEO_SIZE];
+        this.data = new byte[this.RTP_VIDEO_SIZE];
+        this.RTPversion = 0;
+        this.RTPpadding = 0;
+        this.RTPextension = 0;
+        this.RTPcsrc = 0;
+        this.RTPmark = 0;
+        this.RTPpayload = 0;
+        this.RTPsequence = 0;
+        this.RTPtimestamp = 0;
+        this.RTPssrc = 0;
+        this.bService = false;
+        this.remoteIp = "127.0.0.1";
+        this.remotePort = 3002;
+        this.rtpfieldBytes = new byte[4];
+        this.bIframeset = false;
+        this.bIframedoubleset = false;
+        this.bView = false;
+    }
+
+    public void init() {
+        this.RTPversion = 0;
+        this.RTPpadding = 0;
+        this.RTPextension = 0;
+        this.RTPcsrc = 0;
+        this.RTPmark = 0;
+        this.RTPpayload = 0;
+        this.RTPsequence = 0;
+        this.RTPtimestamp = 0;
+        this.RTPssrc = 0;
+        this.bService = false;
+        this.remoteIp = "127.0.0.1";
+        this.remotePort = 3002;
+        this.bIframeset = false;
+        this.bIframedoubleset = false;
+        this.bView = false;
+    }
+
+    public boolean encodeRtpHeader(int payload) {
+        if (this.rtpVideoBuffer == null || this.rtpVideoBuffer.length < 12)
+            return false;
+        int iField = 0;
+        int iAppend = 0;
+        iField = this.RTPversion << 6 & 0xC0;
+        iAppend = this.RTPpadding << 5 & 0x20;
+        iField |= iAppend;
+        iAppend = this.RTPextension << 4 & 0x10;
+        iField |= iAppend;
+        iAppend = this.RTPcsrc & 0xF;
+        iField |= iAppend;
+        this.rtpVideoBuffer[0] = (byte)iField;
+        iField = 0;
+        iField = this.RTPmark << 7 & 0x80;
+        iAppend = payload & 0x7F;
+        iField |= iAppend;
+        this.rtpVideoBuffer[1] = (byte)iField;
+        iField = 0;
+        this.rtpVideoBuffer[2] = (byte)(this.RTPsequence << 16 >> 24);
+        this.rtpVideoBuffer[3] = (byte)(this.RTPsequence << 24 >> 24);
+        this.rtpVideoBuffer[4] = (byte)(this.RTPtimestamp >> 24);
+        this.rtpVideoBuffer[5] = (byte)(this.RTPtimestamp << 8 >> 24);
+        this.rtpVideoBuffer[6] = (byte)(this.RTPtimestamp << 16 >> 24);
+        this.rtpVideoBuffer[7] = (byte)(this.RTPtimestamp << 24 >> 24);
+        this.rtpVideoBuffer[8] = (byte)(this.RTPssrc >> 24);
+        this.rtpVideoBuffer[9] = (byte)(this.RTPssrc << 8 >> 24);
+        this.rtpVideoBuffer[10] = (byte)(this.RTPssrc << 16 >> 24);
+        this.rtpVideoBuffer[11] = (byte)(this.RTPssrc << 24 >> 24);
+        return true;
+    }
+
+    public boolean encodeHNSRtpHeader(int payload, boolean bView) {
+        if (this.rtpVideoBuffer == null || this.rtpVideoBuffer.length < 12)
+            return false;
+        int iField = 0;
+        int iAppend = 0;
+        iField = this.RTPversion << 6 & 0xC0;
+        iAppend = this.RTPpadding << 5 & 0x20;
+        iField |= iAppend;
+        iAppend = this.RTPextension << 4 & 0x10;
+        iField |= iAppend;
+        iAppend = this.RTPcsrc & 0xF;
+        iField |= iAppend;
+        this.rtpVideoBuffer[0] = (byte)iField;
+        iField = 0;
+        iField = this.RTPmark << 7 & 0x80;
+        iAppend = payload & 0x7F;
+        iField |= iAppend;
+        this.rtpVideoBuffer[1] = (byte)iField;
+        iField = 0;
+        this.rtpVideoBuffer[2] = (byte)(this.RTPsequence << 16 >> 24);
+        this.rtpVideoBuffer[3] = (byte)(this.RTPsequence << 24 >> 24);
+        this.rtpVideoBuffer[4] = (byte)(this.RTPtimestamp >> 24);
+        this.rtpVideoBuffer[5] = (byte)(this.RTPtimestamp << 8 >> 24);
+        this.rtpVideoBuffer[6] = (byte)(this.RTPtimestamp << 16 >> 24);
+        this.rtpVideoBuffer[7] = (byte)(this.RTPtimestamp << 24 >> 24);
+        this.rtpVideoBuffer[8] = (byte)(this.RTPssrc >> 24);
+        this.rtpVideoBuffer[9] = (byte)(this.RTPssrc << 8 >> 24);
+        this.rtpVideoBuffer[10] = (byte)(this.RTPssrc << 16 >> 24);
+        this.rtpVideoBuffer[11] = (byte)(this.RTPssrc << 24 >> 24);
+        if (bView) {
+            iField = 1;
+        } else {
+            iField = 0;
+        }
+        this.rtpVideoBuffer[12] = (byte)iField;
+        return true;
+    }
+
+    public boolean parseRTPHeader() {
+        try {
+            this.PARSEversion = 0;
+            this.PARSEpadding = 0;
+            this.PARSEextension = 0;
+            this.PARSEcsrc = 0;
+            this.PARSEmark = 0;
+            this.PARSEpayload = 0;
+            this.PARSEsequence = 0;
+            this.PARSEtimestamp = 0;
+            this.PARSEssrc = 0;
+            this.PARSEview = 0;
+            this.rtpfieldBytes[0] = this.buffer[1];
+            this.PARSEmark = this.rtpfieldBytes[0] >> 7 & 0x1;
+            this.PARSEpayload = this.rtpfieldBytes[0] & Byte.MAX_VALUE;
+        } catch (Exception e) {
+            return false;
+        }
+        return true;
+    }
+
+    public boolean parseHNSRTPHeader() {
+        try {
+            this.PARSEversion = 0;
+            this.PARSEpadding = 0;
+            this.PARSEextension = 0;
+            this.PARSEcsrc = 0;
+            this.PARSEmark = 0;
+            this.PARSEpayload = 0;
+            this.PARSEsequence = 0;
+            this.PARSEtimestamp = 0;
+            this.PARSEssrc = 0;
+            this.PARSEview = 0;
+            this.rtpfieldBytes[0] = this.buffer[1];
+            this.PARSEmark = this.rtpfieldBytes[0] >> 7 & 0x1;
+            this.PARSEpayload = this.rtpfieldBytes[0] & Byte.MAX_VALUE;
+            this.rtpfieldBytes[0] = this.buffer[12];
+            this.PARSEview = this.rtpfieldBytes[0] & 0x1;
+            if (this.PARSEview == 1) {
+                this.bView = true;
+            } else {
+                this.bView = false;
+            }
+        } catch (Exception e) {
+            return false;
+        }
+        return true;
+    }
+}