//public void NotificationReady(string address)
        //{
        //    GetNotifications();
        //}

        /*public void GetNotifications()
         * {
         *  try
         *  {
         *      if (m_notificationsAddress == null)
         *      {
         *          return;
         *      }
         *
         *      string sessionID;
         *      string sessionError;
         *
         *      List<string> notifications = m_publisher.GetNotifications(m_notificationsAddress, out sessionID, out sessionError);
         *
         *      while (sessionError == null && notifications != null && notifications.Count > 0)
         *      {
         *          foreach (string notification in notifications)
         *          {
         *              OutStream.Write(Encoding.ASCII.GetBytes(notification));
         *              OutStream.Flush();
         *          }
         *
         *          notifications = m_publisher.GetNotifications(m_notificationsAddress, out sessionID, out sessionError);
         *      }
         *
         *      if (sessionError != null)
         *      {
         *          throw new ApplicationException(sessionError);
         *      }
         *      //else
         *      //{
         *      //m_publisher.RegisterListener(m_notificationsAddress, NotificationReady);
         *      //}
         *  }
         *  catch (Exception excp)
         *  {
         *      logger.Error("Exception GetNotifications. " + excp.Message);
         *      throw;
         *  }
         * }*/

        /// <summary>
        ///
        /// </summary>
        /// <remarks>
        /// From vt100.net and the vt100 user guide:
        ///
        /// Control Character Octal Code Action Taken
        /// NUL 000 Ignored on input (not stored in input buffer; see full duplex protocol).
        /// ENQ 005 Transmit answerback message.
        /// BEL 007 Sound bell tone from keyboard.
        /// BS 010 Move the cursor to the left one character position, unless it is at the left margin, in which case no action occurs.
        /// HT 011 Move the cursor to the next tab stop, or to the right margin if no further tab stops are present on the line.
        /// LF 012 This code causes a line feed or a new line operation. (See new line mode).
        /// VT 013 Interpreted as LF.
        /// FF 014 Interpreted as LF.
        /// CR 015 Move cursor to the left margin on the current line.
        /// SO 016 Invoke G1 character set, as designated by SCS control sequence.
        /// SI 017 Select G0 character set, as selected by ESC ( sequence.
        /// XON 021 Causes terminal to resume transmission.
        /// XOFF 023 Causes terminal to stop transmitted all codes except XOFF and XON.
        /// CAN 030 If sent during a control sequence, the sequence is immediately terminated and not executed. It also causes the error character to be displayed.
        /// SUB 032 Interpreted as CAN.
        /// ESC 033 Invokes a control sequence.
        /// DEL 177 Ignored on input (not stored in input buffer).
        /// </remarks>
        private void Listen()
        {
            try
            {
                List <char> command    = new List <char>();
                int         cursorPosn = 0;

                while (!HasClosed)
                {
                    byte[] inBuffer  = new byte[1024];
                    int    bytesRead = InStream.Read(inBuffer, 0, 1024);

                    if (bytesRead == 0)
                    {
                        // Connection has been closed.
                        logger.Debug("SIPSorcery SSH connection closed by remote client.");
                        HasClosed = true;
                        break;
                    }

                    //logger.Debug("ssh input received=" + Encoding.ASCII.GetString(inBuffer, 0, bytesRead));

                    // Process any recognised commands.
                    if (inBuffer[0] == 0x03)
                    {
                        // Ctrl-C, disconnect session.
                        Close();
                    }
                    else if (inBuffer[0] == 0x08 || inBuffer[0] == 0x7f)
                    {
                        //logger.Debug("BackSpace");
                        // Backspace, move the cursor left one character and delete the right most character of the current command.
                        if (command.Count > 0)
                        {
                            command.RemoveAt(command.Count - 1);
                            cursorPosn--;
                            // ESC [ 1 D for move left, ESC [ Pn P (Pn=1) for erase single character.
                            OutStream.Write(new byte[] { 0x1b, 0x5b, 0x31, 0x44, 0x1b, 0x5b, 0x31, 0x50 });
                        }
                    }
                    else if (inBuffer[0] == 0x0d || inBuffer[0] == 0x0a)
                    {
                        string commandStr = (command.Count > 0) ? new string(command.ToArray()) : null;
                        logger.Debug("User " + Username + " requested filter=" + commandStr + ".");
                        ProcessCommand(commandStr);

                        command.Clear();
                        cursorPosn = 0;
                    }
                    else if (inBuffer[0] == 0x1b)
                    {
                        // ESC command sequence.
                        //logger.Debug("ESC command sequence: " + BitConverter.ToString(inBuffer, 0, bytesRead));
                        if (inBuffer[1] == 0x5b)
                        {
                            // Arrow scrolling command.
                            if (inBuffer[2] == 0x44)
                            {
                                // Left arrow.
                                if (command.Count > 0 && cursorPosn > 0)
                                {
                                    cursorPosn--;
                                    OutStream.Write(new byte[] { 0x1b, 0x5b, 0x44 });
                                }
                            }
                            else if (inBuffer[2] == 0x43)
                            {
                                // Right arrow.
                                if (command.Count > 0 && cursorPosn < command.Count)
                                {
                                    cursorPosn++;
                                    OutStream.Write(new byte[] { 0x1b, 0x5b, 0x43 });
                                }
                            }
                        }
                    }
                    else if (inBuffer[0] <= 0x1f)
                    {
                        //logger.Debug("Unknown control sequence: " + BitConverter.ToString(inBuffer, 0, bytesRead));
                    }
                    else if (m_notificationsSessionID != null)
                    {
                        if (inBuffer[0] == 's' || inBuffer[0] == 'S')
                        {
                            // Stop events.
                            //StopPolling = true;
                            logger.Debug("Closing session " + m_notificationsSessionID + ".");
                            m_publisher.CloseSession(m_notificationsAddress, m_notificationsSessionID);
                            m_notificationsSessionID = null;
                            OutStream.Write(Encoding.ASCII.GetBytes(CRLF + FILTER_COMMAND_PROMPT));
                        }
                    }
                    else
                    {
                        for (int index = 0; index < bytesRead; index++)
                        {
                            if (command.Count == 0 || cursorPosn == command.Count)
                            {
                                command.Add((char)inBuffer[index]);
                                cursorPosn++;
                            }
                            else
                            {
                                command[cursorPosn] = (char)inBuffer[index];
                                cursorPosn++;
                            }

                            if (command.Count > MAX_COMMAND_LENGTH)
                            {
                                command.Clear();
                                cursorPosn = 0;
                                WriteError("Command too long.");
                                break;
                            }
                            else
                            {
                                // Echo the character back to the client.
                                OutStream.WriteByte(inBuffer[index]);
                            }
                        }
                    }
                }
            }
            catch (Exception excp)
            {
                logger.Error("Exception SIPSorceryVT100Server Listen. " + excp.Message);
            }
        }
        /// <summary>
        /// Attempts to renew an existing subscription.
        /// </summary>
        /// <returns>The session ID if the renewal was successful or null if it wasn't.</returns>
        public string RenewSubscription(SIPRequest subscribeRequest, out SIPResponseStatusCodesEnum errorResponse, out string errorReason)
        {
            errorResponse = SIPResponseStatusCodesEnum.None;
            errorReason   = null;

            try
            {
                int    expiry  = subscribeRequest.Header.Expires;
                string toTag   = subscribeRequest.Header.To.ToTag;
                string fromTag = subscribeRequest.Header.From.FromTag;
                string callID  = subscribeRequest.Header.CallId;
                int    cseq    = subscribeRequest.Header.CSeq;

                // Check for an existing subscription.
                SIPEventSubscription existingSubscription = (from sub in m_subscriptions.Values where sub.SubscriptionDialogue.CallId == callID select sub).FirstOrDefault();

                if (existingSubscription != null)
                {
                    if (expiry == 0)
                    {
                        // Subsciption is being cancelled.
                        StopSubscription(existingSubscription);
                        return(null);
                    }
                    else if (cseq > existingSubscription.SubscriptionDialogue.RemoteCSeq)
                    {
                        logger.Debug("Renewing subscription for " + existingSubscription.SessionID + " and " + existingSubscription.SubscriptionDialogue.Owner + ".");
                        existingSubscription.SubscriptionDialogue.RemoteCSeq = cseq;
                        //existingSubscription.ProxySendFrom = (!subscribeRequest.Header.ProxyReceivedOn.IsNullOrBlank()) ? SIPEndPoint.ParseSIPEndPoint(subscribeRequest.Header.ProxyReceivedOn) : null;

                        string extensionResult = m_publisher.ExtendSession(m_notificationsAddress, existingSubscription.SessionID, expiry);
                        if (extensionResult != null)
                        {
                            // One or more of the monitor servers could not extend the session. Close all the existing sessions and re-create.
                            MonitorLogEvent_External(new SIPMonitorConsoleEvent(SIPMonitorServerTypesEnum.Notifier, SIPMonitorEventTypesEnum.SubscribeFailed, "Monitor session extension for " + existingSubscription.SubscriptionEventPackage.ToString() + " " + existingSubscription.ResourceURI.ToString() + " failed. " + extensionResult, existingSubscription.SubscriptionDialogue.Owner));
                            m_publisher.CloseSession(m_notificationsAddress, existingSubscription.SessionID);

                            // Need to re-establish the sessions with the notification servers.
                            string subscribeError = null;
                            string sessionID      = Guid.NewGuid().ToString();
                            m_publisher.Subscribe(existingSubscription.SubscriptionDialogue.Owner, existingSubscription.SubscriptionDialogue.AdminMemberId, m_notificationsAddress, sessionID, SIPMonitorClientTypesEnum.Machine.ToString(), existingSubscription.MonitorFilter, expiry, null, out subscribeError);

                            if (subscribeError != null)
                            {
                                throw new ApplicationException(subscribeError);
                            }
                            else
                            {
                                lock (m_subscriptions)
                                {
                                    m_subscriptions.Remove(existingSubscription.SessionID);
                                    existingSubscription.SessionID = sessionID;
                                    m_subscriptions.Add(sessionID, existingSubscription);
                                }
                                MonitorLogEvent_External(new SIPMonitorConsoleEvent(SIPMonitorServerTypesEnum.Notifier, SIPMonitorEventTypesEnum.SubscribeAccept, "Monitor session recreated for " + existingSubscription.SubscriptionEventPackage.ToString() + " " + existingSubscription.ResourceURI.ToString() + ".", existingSubscription.SubscriptionDialogue.Owner));
                            }
                        }

                        MonitorLogEvent_External(new SIPMonitorConsoleEvent(SIPMonitorServerTypesEnum.Notifier, SIPMonitorEventTypesEnum.SubscribeRenew, "Monitor session successfully renewed for " + existingSubscription.SubscriptionEventPackage.ToString() + " " + existingSubscription.ResourceURI.ToString() + ".", existingSubscription.SubscriptionDialogue.Owner));

                        return(existingSubscription.SessionID);
                    }
                    else
                    {
                        throw new ApplicationException("A duplicate SUBSCRIBE request was received by NotifierSubscriptionsManager.");
                    }
                }
                else
                {
                    //throw new ApplicationException("No existing subscription could be found for a subscribe renewal request.");
                    errorResponse = SIPResponseStatusCodesEnum.CallLegTransactionDoesNotExist;
                    errorReason   = "Subscription dialog not found";
                    return(null);
                }
            }
            catch (Exception excp)
            {
                logger.Error("Exception RenewSubscription. " + excp.Message);
                throw;
            }
        }
 public void CloseSession(string address, string sessionID)
 {
     m_publisher.CloseSession(address, sessionID);
 }