* #35924: added zrtp module build instructions
diff --git a/jni/libzrtp/src/ZrtpStateClass.cpp b/jni/libzrtp/src/ZrtpStateClass.cpp
new file mode 100644
index 0000000..cff9c6e
--- /dev/null
+++ b/jni/libzrtp/src/ZrtpStateClass.cpp
@@ -0,0 +1,1473 @@
+/*
+  Copyright (C) 2006-2008 Werner Dittmann
+
+  This program is free software: you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation, either version 3 of the License, or
+  (at your option) any later version.
+
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with this program.  If not, see <http://www.gnu.org/licenses/>.
+*/
+
+/**
+ * @author Werner Dittmann <Werner.Dittmann@t-online.de>
+ */
+
+#include <iostream>
+#include <cstdlib>
+#include <ctype.h>
+
+#include <libzrtpcpp/ZRtp.h>
+#include <libzrtpcpp/ZrtpStateClass.h>
+
+using namespace std;
+using namespace GnuZrtpCodes;
+
+state_t states[numberOfStates] = {
+    {Initial,      &ZrtpStateClass::evInitial },
+    {Detect,       &ZrtpStateClass::evDetect },
+    {AckDetected,  &ZrtpStateClass::evAckDetected },
+    {AckSent,      &ZrtpStateClass::evAckSent },
+    {WaitCommit,   &ZrtpStateClass::evWaitCommit },
+    {CommitSent,   &ZrtpStateClass::evCommitSent },
+    {WaitDHPart2,  &ZrtpStateClass::evWaitDHPart2 },
+    {WaitConfirm1, &ZrtpStateClass::evWaitConfirm1 },
+    {WaitConfirm2, &ZrtpStateClass::evWaitConfirm2 },
+    {WaitConfAck,  &ZrtpStateClass::evWaitConfAck },
+    {WaitClearAck, &ZrtpStateClass::evWaitClearAck },
+    {SecureState,  &ZrtpStateClass::evSecureState },
+    {WaitErrorAck, &ZrtpStateClass::evWaitErrorAck }
+};
+
+
+ZrtpStateClass::ZrtpStateClass(ZRtp *p) {
+    parent = p;
+    secSubstate = Normal;
+    engine = new ZrtpStates(states, numberOfStates, Initial);
+
+    commitPkt = NULL;
+    multiStream = false;
+
+    // Set up timers according to ZRTP spec
+    T1.start = 50;
+    T1.maxResend = 20;
+    T1.capping = 200;
+
+    T2.start = 150;
+    T2.maxResend = 10;
+    T2.capping = 600;
+}
+
+ZrtpStateClass::~ZrtpStateClass(void) {
+
+    // If not in Initial state: close the protocol engine
+    // before destroying it. This will free pending packets
+    // if necessary.
+    if (!inState(Initial)) {
+        Event_t ev;
+
+        cancelTimer();
+        ev.type = ZrtpClose;
+        event = &ev;
+        engine->processEvent(*this);
+    }
+    delete engine;
+}
+
+void ZrtpStateClass::processEvent(Event_t *ev) {
+
+    event = ev;
+    char *msg, first, middle, last;
+    uint8_t *pkt;
+
+    parent->synchEnter();
+
+    if (event->type == ZrtpPacket) {
+	pkt = event->packet;
+	msg = (char *)pkt + 4;
+	first = tolower(*msg);
+	middle = tolower(*(msg+4));
+        last = tolower(*(msg+7));
+
+        // Check if this is an Error packet.
+	if (first == 'e' && middle =='r' && last == ' ') {
+            /*
+             * Process a received Error packet.
+             *
+             * In any case stop timer to prevent resending packets.
+             * Use callback method to prepare and get an ErrorAck packet.
+             * Modify event type to "ErrorPkt" and hand it over to current
+             * state for further processing.
+             */
+            cancelTimer();
+            ZrtpPacketError epkt(pkt);
+            ZrtpPacketErrorAck* eapkt = parent->prepareErrorAck(&epkt);
+            parent->sendPacketZRTP(static_cast<ZrtpPacketBase *>(eapkt));
+            event->type = ErrorPkt;
+        }
+        else if (first == 'p' && middle == ' ' && last == ' ') {
+            ZrtpPacketPing ppkt(pkt);
+            ZrtpPacketPingAck* ppktAck = parent->preparePingAck(&ppkt);
+            if (ppktAck != NULL) {          // ACK only to valid PING packet, otherwise ignore it 
+                parent->sendPacketZRTP(static_cast<ZrtpPacketBase *>(ppktAck));
+            }
+            parent->synchLeave();
+            return;
+        }
+        else if (first == 's' && last == 'y') {
+            uint32_t errorCode = 0;
+            ZrtpPacketSASrelay* srly = new ZrtpPacketSASrelay(pkt);
+            ZrtpPacketRelayAck* rapkt = parent->prepareRelayAck(srly, &errorCode);
+            parent->sendPacketZRTP(static_cast<ZrtpPacketBase *>(rapkt));
+            parent->synchLeave();
+            return;
+        }
+
+    }
+    /*
+     * Shut down protocol state engine: cancel outstanding timer, further
+     * processing in current state.
+     */
+    else if (event->type == ZrtpClose) {
+        cancelTimer();
+    }
+    engine->processEvent(*this);
+    parent->synchLeave();
+}
+
+
+void ZrtpStateClass::evInitial(void) {
+    DEBUGOUT((cout << "Checking for match in Initial.\n"));
+
+    if (event->type == ZrtpInitial) {
+	ZrtpPacketHello* hello = parent->prepareHello();
+
+	// remember packet for easy resend in case timer triggers
+	sentPacket = static_cast<ZrtpPacketBase *>(hello);
+
+        if (!parent->sendPacketZRTP(sentPacket)) {
+            sendFailed();                 // returns to state Initial
+            return;
+        }
+        if (startTimer(&T1) <= 0) {
+            timerFailed(SevereNoTimer);      // returns to state Initial
+            return;
+        }
+	nextState(Detect);
+    }
+}
+
+/*
+ * Detect state.
+ *
+ * When in this state the protocol engine sent an initial Hello packet
+ * to the peer.
+ *
+ * When entering this state transition function then:
+ * - Assume Initiator mode, mode may change later on peer reaction
+ * - Instance variable sentPacket contains the sent Hello packet
+ * - Hello timer T1 may be active. This is the case if the other peer
+ *   has prepared its RTP session and answers our Hello packets nearly 
+ *   immediately, i.e. before the Hello timeout counter expires. If the
+ *   other peer does not send a Hello during this time the state engine
+ *   reports "other peer does not support ZRTP" but stays
+ *   in state Detect with no active timer (passiv mode). Staying in state 
+ *   Detect allows another peer to start its detect phase any time later.
+ *
+ *   This restart capability is the reason why we use "startTimer(&T1)" in 
+ *   case we received a Hello packet from another peer. This effectively 
+ *   restarts the Hello timeout counter.
+ *
+ *   In this state we also handle ZrtpInitialize event. This forces a
+ *   restart of ZRTP discovery if an application calls ZrtpQueue#startZrtp
+ *   again. This may happen after a previous discovery phase were not 
+ *   successful.
+ *
+ *   Usually applications use some sort of signaling protocol, for example
+ *   SIP, to negotiate the RTP parameters. Thus the RTP sessions setup is
+ *   fairly sychronized and thus also the ZRTP detection phase. Applications
+ *   that use some other ways to setup the RTP sessions this restart capability
+ *   comes in handy because no RTP setup sychronization is necessary.
+ * 
+ * Possible events in this state are:
+ * - timeout for sent Hello packet: causes a resend check and 
+ *   repeat sending of Hello packet
+ * - received a HelloAck: stop active timer, prepare and send Hello packet,
+ *   switch to state AckDeteced.
+ * - received a Hello: stop active timer, send HelloAck, prepare Commit 
+ *   packet, switch to state AckSent.
+ *
+ */
+void ZrtpStateClass::evDetect(void) {
+
+    DEBUGOUT((cout << "Checking for match in Detect.\n"));
+
+    char *msg, first, last;
+    uint8_t *pkt;
+    uint32_t errorCode = 0;
+
+    /*
+     * First check the general event type, then discrimnate
+     * the real event.
+     */
+    if (event->type == ZrtpPacket) {
+        pkt = event->packet;
+        msg = (char *)pkt + 4;
+
+        first = tolower(*msg);
+        last = tolower(*(msg+7));
+        /*
+         * HelloAck:
+         * - our peer acknowledged our Hello packet, we have not seen the peer's Hello yet
+         * - cancel timer T1 to stop resending Hello
+         * - switch to state AckDetected, wait for peer's Hello (F3)
+         */
+        if (first == 'h' && last =='k') {
+            cancelTimer();
+            sentPacket = NULL;
+            nextState(AckDetected);
+            return;
+        }
+        /*
+         * Hello:
+         * - send HelloAck packet to acknowledge the received Hello packet 
+         * - use received Hello packet to prepare own Commit packet. We need to
+         *   do it at this point because we need the hash value computed from
+         *   peer's Hello packet. Follwing states my use the prepared Commit.
+         * - switch to new state AckSent which sends own Hello packet until 
+         *   peer acknowledges this
+         * - Don't clear sentPacket, points to Hello
+         */
+        if (first == 'h' && last ==' ') {
+            cancelTimer();
+            ZrtpPacketHelloAck* helloAck = parent->prepareHelloAck();
+
+            if (!parent->sendPacketZRTP(static_cast<ZrtpPacketBase *>(helloAck))) {
+                parent->zrtpNegotiationFailed(Severe, SevereCannotSend);
+                return;
+            }
+            // Use peer's Hello packet to create my commit packet, store it 
+            // for possible later usage in state AckSent
+            ZrtpPacketHello hpkt(pkt);
+            commitPkt = parent->prepareCommit(&hpkt, &errorCode);
+
+            nextState(AckSent);
+            if (commitPkt == NULL) {
+                sendErrorPacket(errorCode);    // switches to Error state
+                return;
+            }
+            if (startTimer(&T1) <= 0) {        // restart own Hello timer/counter
+                timerFailed(SevereNoTimer);    // returns to state Initial
+            }
+            T1.maxResend = 60;                 // more retries to extend time, see chap. 6
+        }
+        return;      // unknown packet for this state - Just ignore it
+    }
+    // Timer event triggered - this is Timer T1 to resend Hello
+    else if (event->type == Timer) {
+        if (!parent->sendPacketZRTP(sentPacket)) {
+            sendFailed();       // returns to state Initial
+            return;
+        }
+        if (nextTimer(&T1) <= 0) {
+            commitPkt = NULL;
+            parent->zrtpNotSuppOther();
+            nextState(Detect);
+        }
+    }
+    // If application call zrtpStart() to restart discovery
+    else if (event->type == ZrtpInitial) {
+        cancelTimer();
+        if (!parent->sendPacketZRTP(sentPacket)) {
+            sendFailed();                 // returns to state Initial
+            return;
+        }
+        if (startTimer(&T1) <= 0) {
+            timerFailed(SevereNoTimer);   // returns to state Initial
+        }
+    }
+    else { // unknown Event type for this state (covers Error and ZrtpClose)
+        if (event->type != ZrtpClose) {
+            parent->zrtpNegotiationFailed(Severe, SevereProtocolError);
+        }
+        sentPacket = NULL;
+        nextState(Initial);
+    }
+}
+
+/*
+ * AckSent state.
+ *
+ * The protocol engine got a Hello packet from peer and answered with a
+ * HelloAck response.  According to the protocol we must also send a 
+ * Hello after HelloAck (refer to figure 1 in ZRTP RFC xxxx, message 
+ * HelloACK (F2) must be followed by Hello (F3)). We use the timeout in 
+ * this state to send the required Hello (F3).
+ *
+ * Our peer must acknowledge the Hello with HelloAck. In earlier versions 
+ * also a Commit was a valid packet thus the code covers this.
+ * Figure 1 in the RFC shows the HelloAck, chapter 7 states that a Commit 
+ * may be send to acknowledge Hello. There is one constraint when using a Commit to
+ * acknowledge Hello: refer to chapter 4.1 that requires that both parties
+ * have completed the Hello/HelloAck discovery handshake. This implies that 
+ * only message F4 may be replaced by a Commit. This constraint guarantees
+ * that both peers have seen at least one Hello.
+ *
+ * When entering this transition function:
+ * - The instance variabe sentPacket contains own Hello packet
+ * - The instance variabe commitPkt points to prepared Commit packet 
+ * - Timer T1 is active
+ *
+ * Possible events in this state are:
+ * - timeout for sent Hello packet: causes a resend check and repeat sending
+ *   of Hello packet
+ * - HelloAck: The peer answered with HelloAck to own HelloAck/Hello. Send
+ *   prepared Commit packet and try Initiator mode.
+ * - Commit: The peer answered with Commit to HelloAck/Hello, thus switch to
+ *   responder mode.
+ * - Hello: If the protcol engine receives another Hello it repeats the 
+ *   HelloAck/Hello response until Timer T1 exceeds its maximum. This may 
+ *   happen if the other peer sends Hello only (maybe due to network problems)
+ */
+void ZrtpStateClass::evAckSent(void) {
+
+    DEBUGOUT((cout << "Checking for match in AckSent.\n"));
+
+    char *msg, first, last;
+    uint8_t *pkt;
+    uint32_t errorCode = 0;
+
+    /*
+     * First check the general event type, then discrimnate
+     * the real event.
+     */
+    if (event->type == ZrtpPacket) {
+        pkt = event->packet;
+	msg = (char *)pkt + 4;
+
+	first = tolower(*msg);
+	last = tolower(*(msg+7));
+
+	/*
+         * HelloAck:
+         * The peer answers with HelloAck to own HelloAck/Hello. Send Commit
+         * and try Initiator mode. The requirement defined in chapter 4.1 to
+         * have a complete Hello/HelloAck is fulfilled.
+	 * - stop Hello timer T1
+	 * - send own Commit message
+	 * - switch state to CommitSent, start Commit timer, assume Initiator
+	 */
+	if (first == 'h' && last =='k') {
+	    cancelTimer();
+
+            // remember packet for easy resend in case timer triggers
+            // Timer trigger received in new state CommitSend
+            sentPacket = static_cast<ZrtpPacketBase *>(commitPkt);
+            commitPkt = NULL;                    // now stored in sentPacket
+	    nextState(CommitSent);
+            if (!parent->sendPacketZRTP(sentPacket)) {
+                sendFailed();             // returns to state Initial
+                return;
+            }
+            if (startTimer(&T2) <= 0) {
+                timerFailed(SevereNoTimer);  // returns to state Initial
+	    }
+	    return;
+        }
+        /*
+         * Hello:
+         * - peer didn't receive our HelloAck
+         * - repeat HelloAck/Hello response:
+         *  -- get HelloAck packet, send it
+         *  -- The timeout trigger of T1 sends our Hello packet
+         *  -- stay in state AckSent
+         *
+         * Similar to Detect state: just acknowledge the Hello, the next
+         * timeout sends the following Hello.
+         */
+
+        if (first == 'h' && last ==' ') {
+            ZrtpPacketHelloAck* helloAck = parent->prepareHelloAck();
+
+            if (!parent->sendPacketZRTP(static_cast<ZrtpPacketBase *>(helloAck))) {
+                nextState(Detect);
+                parent->zrtpNegotiationFailed(Severe, SevereCannotSend);
+            }
+            return;
+        }
+        /*
+         * Commit:
+         * The peer answers with Commit to HelloAck/Hello, thus switch to
+         * responder mode.
+         * - stop timer T1
+         * - prepare and send our DHPart1
+         * - switch to state WaitDHPart2 and wait for peer's DHPart2
+         * - don't start timer, we are responder
+         */
+        if (first == 'c') {
+            cancelTimer();
+            ZrtpPacketCommit cpkt(pkt);
+
+            if (!multiStream) {
+                ZrtpPacketDHPart* dhPart1 = parent->prepareDHPart1(&cpkt, &errorCode);
+
+                // Something went wrong during processing of the Commit packet
+                if (dhPart1 == NULL) {
+                    if (errorCode != IgnorePacket) {
+                        sendErrorPacket(errorCode);
+                    }
+                    return;
+                }
+                commitPkt = NULL;
+                sentPacket = static_cast<ZrtpPacketBase *>(dhPart1);
+                nextState(WaitDHPart2);
+            }
+            else {
+                ZrtpPacketConfirm* confirm = parent->prepareConfirm1MultiStream(&cpkt, &errorCode);
+
+                // Something went wrong during processing of the Commit packet
+                if (confirm == NULL) {
+                    if (errorCode != IgnorePacket) {
+                        sendErrorPacket(errorCode);
+                    }
+                    return;
+                }
+                sentPacket = static_cast<ZrtpPacketBase *>(confirm);
+                nextState(WaitConfirm2);
+            }
+            if (!parent->sendPacketZRTP(sentPacket)) {
+                sendFailed();      // returns to state Initial
+            }
+        }
+    }
+    /*
+     * Timer:
+     * - resend Hello packet, stay in state, restart timer until repeat 
+     *   counter triggers
+     * - if repeat counter triggers switch to state Detect, con't clear
+     *   sentPacket, Detect requires it to point to own Hello message
+     */
+    else if (event->type == Timer) {
+        if (!parent->sendPacketZRTP(sentPacket)) {
+            return sendFailed();      // returns to state Initial
+        }
+        if (nextTimer(&T1) <= 0) {
+            parent->zrtpNotSuppOther();
+            commitPkt = NULL;
+            // Stay in state Detect to be prepared get an hello from
+            // other peer any time later
+            nextState(Detect);
+        }
+    }
+    else {   // unknown Event type for this state (covers Error and ZrtpClose)
+        if (event->type != ZrtpClose) {
+            parent->zrtpNegotiationFailed(Severe, SevereProtocolError);
+        }
+        commitPkt = NULL;
+        sentPacket = NULL;
+        nextState(Initial);
+    }
+}
+/*
+ * AckDetected state.
+ *
+ * The protocol engine received a HelloAck in state Detect, thus the peer 
+ * acknowledged our the Hello. According to ZRT RFC xxxx our peer must send
+ * its Hello until our protocol engine sees it (refer also to comment for
+ * state AckSent). This protocol sequence gurantees that both peers got at
+ * least one Hello. 
+ *
+ * When entering this transition function
+ * - instance variable sentPacket is NULL, Hello timer stopped
+ *
+ * Possible events in this state are:
+ * Hello: we have to choices
+ *  1) we can acknowledge the peer's Hello with a HelloAck
+ *  2) we can acknowledge the peer's Hello with a Commit
+ *  Both choices are implemented and may be enabled by setting a compile
+ *  time #if (see code below). Currently we use choice 1) here because
+ *  it's more aligned to the ZRTP specification
+ */
+void ZrtpStateClass::evAckDetected(void) {
+
+    DEBUGOUT((cout << "Checking for match in AckDetected.\n"));
+
+    char *msg, first, last;
+    uint8_t *pkt;
+    uint32_t errorCode = 0;
+
+    if (event->type == ZrtpPacket) {
+        pkt = event->packet;
+        msg = (char *)pkt + 4;
+
+        first = tolower(*msg);
+        last = tolower(*(msg+7));
+
+#if 1
+        /*
+         * Implementation for choice 1)
+         * Hello:
+         * - Acknowledge peers Hello, sending HelloACK (F4)
+         * - switch to state WaitCommit, wait for peer's Commit
+         * - we are going to be in the Responder role
+         */
+
+        if (first == 'h' && last ==' ') {
+            // Parse Hello packet and build an own Commit packet even if the
+            // Commit is not send to the peer. We need to do this to check the
+            // Hello packet and prepare the shared secret stuff.
+            ZrtpPacketHello hpkt(pkt);
+            ZrtpPacketCommit* commit = parent->prepareCommit(&hpkt, &errorCode);
+
+            // Something went wrong during processing of the Hello packet, for
+            // example wrong version, duplicate ZID.
+            if (commit == NULL) {
+                sendErrorPacket(errorCode);
+                return;
+            }
+            ZrtpPacketHelloAck *helloAck = parent->prepareHelloAck();
+            nextState(WaitCommit);
+
+            // remember packet for easy resend
+            sentPacket = static_cast<ZrtpPacketBase *>(helloAck);
+            if (!parent->sendPacketZRTP(static_cast<ZrtpPacketBase *>(helloAck))) {
+                sendFailed();
+            }
+        }
+#else
+        /*
+         * Implementation for choice 2)
+         * Hello:
+         * - Acknowledge peers Hello by sending Commit (F5)
+         *   instead of HelloAck (F4)
+         * - switch to state CommitSent
+         * - Initiator role, thus start timer T2 to monitor timeout for Commit
+         */
+
+        if (first == 'h') {
+            // Parse peer's packet data into a Hello packet
+            ZrtpPacketHello hpkt(pkt);
+            ZrtpPacketCommit* commit = parent->prepareCommit(&hpkt, &errorCode);
+            // Something went wrong during processing of the Hello packet  
+            if (commit == NULL) {
+                sendErrorPacket(errorCode);
+                return;
+            }
+            nextState(CommitSent);
+
+            // remember packet for easy resend in case timer triggers
+            // Timer trigger received in new state CommitSend
+            sentPacket = static_cast<ZrtpPacketBase *>(commit);
+            if (!parent->sendPacketZRTP(sentPacket)) {
+                sendFailed();
+                return;
+            }
+            if (startTimer(&T2) <= 0) {
+                timerFailed(SevereNoTimer);
+            }
+        }
+#endif
+    }
+    else {  // unknown Event type for this state (covers Error and ZrtpClose)
+        if (event->type != ZrtpClose) {
+            parent->zrtpNegotiationFailed(Severe, SevereProtocolError);
+        }
+        nextState(Initial);
+    }
+}
+
+/*
+ * WaitCommit state.
+ *
+ * This state is only used if we use choice 1) in AckDetected.
+ *
+ * When entering this transition function
+ * - instance variable sentPacket contains a HelloAck packet
+ * 
+ * Possible events in this state are:
+ * - Hello: just resend our HelloAck
+ * - Commit: prepare and send our DHPart1 message to start first
+ *   half of DH key agreement. Switch to state WaitDHPart2, don't
+ *   start any timer, we a Responder.
+ */
+void ZrtpStateClass::evWaitCommit(void) {
+
+    DEBUGOUT((cout << "Checking for match in WaitCommit.\n"));
+
+    char *msg, first;
+    uint8_t *pkt;
+    uint32_t errorCode = 0;
+
+    if (event->type == ZrtpPacket) {
+        pkt = event->packet;
+        msg = (char *)pkt + 4;
+
+        first = tolower(*msg);
+        /*
+         * Hello:
+         * - resend HelloAck
+         * - stay in WaitCommit
+         */
+        if (first == 'h') {
+            if (!parent->sendPacketZRTP(sentPacket)) {
+                sendFailed();       // returns to state Initial
+            }
+            return;
+        }
+        /*
+         * Commit:
+         * - prepare DH1Part packet or Confirm1 if multi stream mode
+         * - send it to peer
+         * - switch state to WaitDHPart2 or WaitConfirm2 if multi stream mode
+         * - don't start timer, we are responder
+         */
+        if (first == 'c') {
+            ZrtpPacketCommit cpkt(pkt);
+
+            if (!multiStream) {
+                ZrtpPacketDHPart* dhPart1 = parent->prepareDHPart1(&cpkt, &errorCode);
+
+                // Something went wrong during processing of the Commit packet
+                if (dhPart1 == NULL) {
+                    if (errorCode != IgnorePacket) {
+                        sendErrorPacket(errorCode);
+                    }
+                    return;
+                }
+                sentPacket = static_cast<ZrtpPacketBase *>(dhPart1);
+                nextState(WaitDHPart2);
+            }
+            else {
+                ZrtpPacketConfirm* confirm = parent->prepareConfirm1MultiStream(&cpkt, &errorCode);
+
+                // Something went wrong during processing of the Commit packet
+                if (confirm == NULL) {
+                    if (errorCode != IgnorePacket) {
+                        sendErrorPacket(errorCode);
+                    }
+                    return;
+                }
+                sentPacket = static_cast<ZrtpPacketBase *>(confirm);
+                nextState(WaitConfirm2);
+            }
+            if (!parent->sendPacketZRTP(sentPacket)) {
+                sendFailed();       // returns to state Initial
+            }
+        }
+    }
+    else {  // unknown Event type for this state (covers Error and ZrtpClose)
+        if (event->type != ZrtpClose) {
+            parent->zrtpNegotiationFailed(Severe, SevereProtocolError);
+        }
+        sentPacket = NULL;
+        nextState(Initial);
+    }
+}
+
+/*
+ * CommitSent state.
+ *
+ * This state either handles a DH1Part1 message to start the first
+ * half of DH key agreement or it handles a Commit clash. If handling a
+ * Commit clash it may happen that we change our role from Initiator to
+ * Responder.
+ *
+ * When entering this transition function
+ * - assume Initiator mode, may change if we reveice a Commit here
+ * - sentPacket contains Commit packet
+ * - Commit timer (T2) active
+ *
+ * Possible events in this state are:
+ * - timeout for sent Commit packet: causes a resend check and repeat sending
+ *   of Commit packet
+ * - Commit: This is a Commit clash. Break the tie accroding to chapter 5.2
+ * - DHPart1: start first half of DH key agreement. Perpare and send own DHPart2
+ *   and switch to state WaitConfirm1.
+ */
+
+void ZrtpStateClass::evCommitSent(void) {
+
+    DEBUGOUT((cout << "Checking for match in CommitSend.\n"));
+
+    char *msg, first, last;
+    uint8_t *pkt;
+    uint32_t errorCode = 0;
+
+    if (event->type == ZrtpPacket) {
+        pkt = event->packet;
+        msg = (char *)pkt + 4;
+
+        first = tolower(*msg);
+        last = tolower(*(msg+7));
+
+        /*
+         * HelloAck or Hello:
+         * - delayed "HelloAck" or "Hello", maybe due to network latency, just 
+         *   ignore it
+         * - no switch in state, leave timer as it is
+         */
+        if (first == 'h' && (last =='k' || last == ' ')) {
+            return;
+        }
+
+        /*
+         * Commit:
+         * We have a "Commit" clash. Resolve it.
+         *
+         * - switch off resending Commit
+         * - compare my hvi with peer's hvi
+         * - if my hvi is greater
+         *   - we are Initiator, stay in state, wait for peer's DHPart1 packet
+         * - else
+         *   - we are Responder, stop timer
+         *   - prepare and send DH1Packt,
+         *   - switch to state WaitDHPart2, implies Responder path
+         */
+        if (first == 'c' && last == ' ') {
+            ZrtpPacketCommit zpCo(pkt);
+
+            if (!parent->verifyH2(&zpCo)) {
+                return;
+            }
+            cancelTimer();         // this cancels the Commit timer T2
+
+            // if our hvi is less than peer's hvi: switch to Responder mode and
+            // send DHPart1 or Confirm1 packet. Peer (as Initiator) will retrigger if
+            // necessary
+            //
+            if (parent->compareCommit(&zpCo) < 0) {
+                if (!multiStream) {
+                    ZrtpPacketDHPart* dhPart1 = parent->prepareDHPart1(&zpCo, &errorCode);
+
+                    // Something went wrong during processing of the Commit packet
+                    if (dhPart1 == NULL) {
+                        if (errorCode != IgnorePacket) {
+                            sendErrorPacket(errorCode);
+                        }
+                        return;
+                    }
+                    nextState(WaitDHPart2);
+                    sentPacket = static_cast<ZrtpPacketBase *>(dhPart1);
+                }
+                else {
+                    ZrtpPacketConfirm* confirm = parent->prepareConfirm1MultiStream(&zpCo, &errorCode);
+
+                    // Something went wrong during processing of the Commit packet
+                    if (confirm == NULL) {
+                        if (errorCode != IgnorePacket) {
+                            sendErrorPacket(errorCode);
+                        }
+                        return;
+                    }
+                    nextState(WaitConfirm2);
+                    sentPacket = static_cast<ZrtpPacketBase *>(confirm);
+                }
+                if (!parent->sendPacketZRTP(sentPacket)) {
+                    sendFailed();       // returns to state Initial
+                }
+            }
+            // Stay in state, we are Initiator, wait for DHPart1 of Confirm1 packet from peer.
+            // Resend Commit after timeout until we get a DHPart1 or Confirm1
+            else {
+                if (startTimer(&T2) <= 0) { // restart the Commit timer, gives peer more time to react
+                    timerFailed(SevereNoTimer);    // returns to state Initial
+                }
+            }
+            return;
+        }
+
+        /*
+         * DHPart1:
+         * - switch off resending Commit
+         * - Prepare and send DHPart2
+         * - switch to WaitConfirm1
+         * - start timer to resend DHPart2 if necessary, we are Initiator
+         */
+        if (first == 'd') {
+            cancelTimer();
+            sentPacket = NULL;
+            ZrtpPacketDHPart dpkt(pkt);
+            ZrtpPacketDHPart* dhPart2 = parent->prepareDHPart2(&dpkt, &errorCode);
+
+            // Something went wrong during processing of the DHPart1 packet
+            if (dhPart2 == NULL) {
+                if (errorCode != IgnorePacket) {
+                    sendErrorPacket(errorCode);
+                }
+                else {
+                    if (startTimer(&T2) <= 0) {
+                        timerFailed(SevereNoTimer);       // switches to state Initial
+                    }
+                }
+
+                return;
+            }
+            sentPacket = static_cast<ZrtpPacketBase *>(dhPart2);
+            nextState(WaitConfirm1);
+
+            if (!parent->sendPacketZRTP(sentPacket)) {
+                sendFailed();       // returns to state Initial
+                return;
+            }
+            if (startTimer(&T2) <= 0) {
+                timerFailed(SevereNoTimer);       // switches to state Initial
+            }
+            return;
+        }
+
+        if (multiStream && (first == 'c' && last == '1')) {
+            cancelTimer();
+            ZrtpPacketConfirm cpkt(pkt);
+
+            ZrtpPacketConfirm* confirm = parent->prepareConfirm2MultiStream(&cpkt, &errorCode);
+
+            // Something went wrong during processing of the Confirm1 packet
+            if (confirm == NULL) {
+                sendErrorPacket(errorCode);
+                return;
+            }
+            nextState(WaitConfAck);
+            sentPacket = static_cast<ZrtpPacketBase *>(confirm);
+
+            if (!parent->sendPacketZRTP(sentPacket)) {
+                sendFailed();         // returns to state Initial
+                return;
+            }
+            if (startTimer(&T2) <= 0) {
+                timerFailed(SevereNoTimer);  // returns to state Initial
+                return;
+            }
+            // according to chap 5.6: after sending Confirm2 the Initiator must
+            // be ready to receive SRTP data. SRTP sender will be enabled in WaitConfAck
+            // state.
+            if (!parent->srtpSecretsReady(ForReceiver)) {
+                parent->sendInfo(Severe, CriticalSWError);
+                sendErrorPacket(CriticalSWError);
+                return;
+            }
+        }
+    }
+    // Timer event triggered, resend the Commit packet
+    else if (event->type == Timer) {
+        if (!parent->sendPacketZRTP(sentPacket)) {
+                sendFailed();       // returns to state Initial
+                return;
+        }
+        if (nextTimer(&T2) <= 0) {
+            timerFailed(SevereTooMuchRetries);       // returns to state Initial
+        }
+    }
+    else {  // unknown Event type for this state (covers Error and ZrtpClose)
+        if (event->type != ZrtpClose) {
+            parent->zrtpNegotiationFailed(Severe, SevereProtocolError);
+        }
+        sentPacket = NULL;
+        nextState(Initial);
+    }
+}
+
+/*
+ * WaitDHPart2 state.
+ *
+ * This state handles the second part of SH key agreement. Only the Resonder
+ * can enter this state.
+ *
+ * When entering this transition function
+ * - sentPacket contains DHPart1 packet, no timer active
+ *
+ * Possible events in this state are:
+ * - Commit: Our peer didn't receive out DHPart1 thus the peer sends Commit again.
+ *   Just repeat our DHPart1.
+ * - DHPart2: start second half of DH key agreement. Perpare and send own Confirm1
+ *   and switch to state WaitConfirm2.
+ */
+void ZrtpStateClass::evWaitDHPart2(void) {
+
+    DEBUGOUT((cout << "Checking for match in DHPart2.\n"));
+
+    char *msg, first;
+    uint8_t *pkt;
+    uint32_t errorCode = 0;
+
+    if (event->type == ZrtpPacket) {
+        pkt = event->packet;
+        msg = (char *)pkt + 4;
+
+        first = tolower(*msg);
+        /*
+         * Commit:
+         * - resend DHPart1
+         * - stay in state
+         */
+        if (first == 'c') {
+            if (!parent->sendPacketZRTP(sentPacket)) {
+                return sendFailed();       // returns to state Initial
+            }
+            return;
+        }
+        /*
+         * DHPart2:
+         * - prepare Confirm1 packet
+         * - switch to WaitConfirm2
+         * - No timer, we are responder
+         */
+        if (first == 'd') {
+            ZrtpPacketDHPart dpkt(pkt);
+            ZrtpPacketConfirm* confirm = parent->prepareConfirm1(&dpkt, &errorCode);
+
+            if (confirm == NULL) {
+                if (errorCode != IgnorePacket) {
+                    sendErrorPacket(errorCode);
+                }
+                return;
+            }
+            nextState(WaitConfirm2);
+            sentPacket = static_cast<ZrtpPacketBase *>(confirm);
+            if (!parent->sendPacketZRTP(sentPacket)) {
+                sendFailed();       // returns to state Initial
+            }
+        }
+    }
+    else {  // unknown Event type for this state (covers Error and ZrtpClose)
+        if (event->type != ZrtpClose) {
+            parent->zrtpNegotiationFailed(Severe, SevereProtocolError);
+        }
+        sentPacket = NULL;
+        nextState(Initial);
+    }
+}
+
+/*
+ * WaitConirm1 state.
+ *
+ * This state handles a received Confirm1 message and only the Initiator
+ * can enter this state.
+ *
+ * When entering this transition function in DH mode:
+ * - Initiator mode
+ * - sentPacket contains DHPart2 packet, DHPart2 timer active
+ *
+ * When entering this transition function in Multi stream mode via AckSent:
+ * - Initiator mode
+ * - sentPacket contains my Commit packet, Commit timer active
+ * 
+* Possible events in this state are:
+ * - timeout for sent DHPart2 packet: causes a resend check and repeat sending
+ *   of DHPart2 packet.
+ * - Confirm1: Check Confirm1 message. If it is ok then prepare and send own
+ *   Confirm2 packet and switch to state WaitConfAck.
+ */
+void ZrtpStateClass::evWaitConfirm1(void) {
+
+    DEBUGOUT((cout << "Checking for match in WaitConfirm1.\n"));
+
+    char *msg, first, last;
+    uint8_t *pkt;
+    uint32_t errorCode = 0;
+
+    if (event->type == ZrtpPacket) {
+        pkt = event->packet;
+        msg = (char *)pkt + 4;
+
+        first = tolower(*msg);
+        last = tolower(*(msg+7));
+
+        /*
+         * Confirm1:
+         * - Switch off resending DHPart2
+         * - prepare a Confirm2 packet
+         * - switch to state WaitConfAck
+         * - set timer to monitor Confirm2 packet, we are initiator
+         */
+        if (first == 'c' && last == '1') {
+            cancelTimer();
+            ZrtpPacketConfirm cpkt(pkt);
+
+            ZrtpPacketConfirm* confirm = parent->prepareConfirm2(&cpkt, &errorCode);
+
+            // Something went wrong during processing of the Confirm1 packet
+            if (confirm == NULL) {
+                sendErrorPacket(errorCode);
+                return;
+            }
+            nextState(WaitConfAck);
+            sentPacket = static_cast<ZrtpPacketBase *>(confirm);
+
+            if (!parent->sendPacketZRTP(sentPacket)) {
+                sendFailed();         // returns to state Initial
+                return;
+            }
+            if (startTimer(&T2) <= 0) {
+                timerFailed(SevereNoTimer);  // returns to state Initial TODO check for return following this line
+            }
+            // according to chap 5.8: after sending Confirm2 the Initiator must
+            // be ready to receive SRTP data. SRTP sender will be enabled in WaitConfAck
+            // state.
+            if (!parent->srtpSecretsReady(ForReceiver)) {
+                parent->sendInfo(Severe, CriticalSWError);
+                sendErrorPacket(CriticalSWError);
+                return;
+            }
+        }
+    }
+    else if (event->type == Timer) {
+        if (!parent->sendPacketZRTP(sentPacket)) {
+            sendFailed();             // returns to state Initial
+            return;
+        }
+        if (nextTimer(&T2) <= 0) {
+            timerFailed(SevereTooMuchRetries);     // returns to state Initial
+        }
+    }
+    else {  // unknown Event type for this state (covers Error and ZrtpClose)
+        if (event->type != ZrtpClose) {
+            parent->zrtpNegotiationFailed(Severe, SevereProtocolError);
+        }
+        sentPacket = NULL;
+        nextState(Initial);
+    }
+}
+
+/*
+ * WaitConfirm2 state.
+ *
+ * Handles the Confirm2 message that closes the key agreement handshake. Only
+ * the Responder can enter this state. If the Confirm2 message is ok send a 
+ * Conf2Ack to our peer. Switch to secure mode after sending Conf2Ack, our 
+ * peer switches to secure mode after receiving Conf2Ack.
+ *
+ * TODO - revise documentation comments
+ * 
+ * When entering this transition function
+ * - Responder mode
+ * - sentPacket contains Confirm1 packet, no timer active
+ *
+ * Possible events in this state are:
+ * - DHPart2: Our peer didn't receive our Confirm1 thus sends DHPart2 again.
+ *   Just repeat our Confirm1.
+ * - Confirm2: close DH key agreement. Perpare and send own Conf2Ack
+ *   and switch to state SecureState.
+ */
+void ZrtpStateClass::evWaitConfirm2(void) {
+
+    DEBUGOUT((cout << "Checking for match in WaitConfirm2.\n"));
+
+    char *msg, first, last;
+    uint8_t *pkt;
+    uint32_t errorCode = 0;
+
+    if (event->type == ZrtpPacket) {
+        pkt = event->packet;
+        msg = (char *)pkt + 4;
+
+        first = tolower(*msg);
+        last = tolower(*(msg+7));
+
+        /*
+         * DHPart2 or Commit in multi stream mode:
+         * - resend Confirm1 packet
+         * - stay in state
+         */
+        if (first == 'd' || (multiStream && (first == 'c' && last == ' '))) {
+            if (!parent->sendPacketZRTP(sentPacket)) {
+                sendFailed();             // returns to state Initial
+            }
+            return;
+        }
+        /*
+         * Confirm2:
+         * - prepare ConfAck
+         * - switch on security (SRTP)
+         * - switch to SecureState
+         */
+        if (first == 'c' && last == '2') {
+            ZrtpPacketConfirm cpkt(pkt);
+            ZrtpPacketConf2Ack* confack = parent->prepareConf2Ack(&cpkt, &errorCode);
+
+            // Something went wrong during processing of the confirm2 packet
+            if (confack == NULL) {
+                sendErrorPacket(errorCode);
+                return;
+            }
+            sentPacket = static_cast<ZrtpPacketBase *>(confack);
+
+            if (!parent->sendPacketZRTP(sentPacket)) {
+                sendFailed();             // returns to state Initial
+                return;
+            }
+            if (!parent->srtpSecretsReady(ForSender) ||
+                !parent->srtpSecretsReady(ForReceiver)) {
+                parent->sendInfo(Severe, CriticalSWError);
+                sendErrorPacket(CriticalSWError);
+                return;
+            }
+            nextState(SecureState);
+            parent->sendInfo(Info, InfoSecureStateOn);
+        }
+    }
+    else {  // unknown Event type for this state (covers Error and ZrtpClose)
+        if (event->type != ZrtpClose) {
+            parent->zrtpNegotiationFailed(Severe, SevereProtocolError);
+        }
+        sentPacket = NULL;
+        nextState(Initial);
+    }
+}
+
+/*
+ * WaitConf2Ack state.
+ *
+ * This state handles the Conf2Ack message that acknowledges the successfull
+ * processing of Confirm2. Only the Initiator can enter this state. Switch on
+ * secure mode and switch to state SecureState.
+ *
+ * When entering this transition function
+ * - Initiator mode
+ * - sentPacket contains Confirm2 packet, Confirm2 timer active
+ * - receiver security switched on
+ *
+ * Possible events in this state are:
+ * - timeout for sent Confirm2 packet: causes a resend check and repeat sending
+ *   of Confirm2 packet
+ * - Conf2Ack: Key agreement was successfull, switch to secure mode.
+ */
+void ZrtpStateClass::evWaitConfAck(void) {
+
+    DEBUGOUT((cout << "Checking for match in WaitConfAck.\n"));
+
+    char *msg, first;
+    uint8_t *pkt;
+
+    if (event->type == ZrtpPacket) {
+        pkt = event->packet;
+        msg = (char *)pkt + 4;
+
+        first = tolower(*msg);
+         /*
+         * ConfAck:
+         * - Switch off resending Confirm2
+         * - switch to SecureState
+         */
+        if (first == 'c') {
+            cancelTimer();
+            sentPacket = NULL;
+            // Receiver was already enabled after sending Confirm2 packet
+            // see previous states.
+            if (!parent->srtpSecretsReady(ForSender)) {
+                parent->sendInfo(Severe, CriticalSWError);
+                sendErrorPacket(CriticalSWError);
+                return;
+            }
+            nextState(SecureState);
+            // TODO: call parent to clear signature data at initiator
+            parent->sendInfo(Info, InfoSecureStateOn);
+        }
+    }
+    else if (event->type == Timer) {
+        if (!parent->sendPacketZRTP(sentPacket)) {
+            sendFailed();             // returns to state Initial
+            parent->srtpSecretsOff(ForReceiver);
+            return;
+        }
+        if (nextTimer(&T2) <= 0) {
+            timerFailed(SevereTooMuchRetries); // returns to state Initial
+            parent->srtpSecretsOff(ForReceiver);
+        }
+    }
+    else {  // unknown Event type for this state (covers Error and ZrtpClose)
+        if (event->type != ZrtpClose) {
+            parent->zrtpNegotiationFailed(Severe, SevereProtocolError);
+        }
+        sentPacket = NULL;
+        nextState(Initial);
+        parent->srtpSecretsOff(ForReceiver);
+    }
+}
+
+/*
+ * When entering this transition function
+ * - sentPacket contains GoClear packet, GoClear timer active
+ */
+
+void ZrtpStateClass::evWaitClearAck(void) {
+    DEBUGOUT((cout << "Checking for match in ClearAck.\n"));
+
+    char *msg, first, last;
+    uint8_t *pkt;
+
+    if (event->type == ZrtpPacket) {
+	pkt = event->packet;
+	msg = (char *)pkt + 4;
+
+	first = tolower(*msg);
+	last = tolower(*(msg+7));
+
+	/*
+	 * ClearAck:
+	 * - stop resending GoClear,
+	 * - switch to state AckDetected, wait for peer's Hello
+	 */
+	if (first == 'c' && last =='k') {
+	    cancelTimer();
+	    sentPacket = NULL;
+	    nextState(Initial);
+	}
+    }
+    // Timer event triggered - this is Timer T2 to resend GoClear w/o HMAC
+    else if (event->type == Timer) {
+        if (!parent->sendPacketZRTP(sentPacket)) {
+            sendFailed();                 // returns to state Initial
+            return;
+        }
+        if (nextTimer(&T2) <= 0) {
+            timerFailed(SevereTooMuchRetries);     // returns to state Initial
+        }
+    }
+    else {  // unknown Event type for this state (covers Error and ZrtpClose)
+        if (event->type != ZrtpClose) {
+            parent->zrtpNegotiationFailed(Severe, SevereProtocolError);
+        }
+	sentPacket = NULL;
+	nextState(Initial);
+    }
+}
+
+
+/*
+ * WaitErrorAck state.
+ *
+ * This state belongs to the "error handling state overlay" and handle
+ * ErrorAck message. Most of the ZRTP states can send Error message for
+ * example if they detect wrong packets. After sending an Error message
+ * the protocol engine switches to WaitErrorAck state. Receiving an
+ * ErrorAck message completes the ZRTP error handling.
+ *
+ * When entering this transition function
+ * - sentPacket contains Error packet, Error timer active
+ *
+ * Possible events in this state are:
+ * - timeout for sent Error packet: causes a resend check and repeat sending
+ *   of Error packet
+ * - ErrorAck: Stop timer and switch to state Initial.
+ */
+
+void ZrtpStateClass::evWaitErrorAck(void) {
+    DEBUGOUT((cout << "Checking for match in ErrorAck.\n"));
+
+    char *msg, first, last;
+    uint8_t *pkt;
+
+    if (event->type == ZrtpPacket) {
+        pkt = event->packet;
+        msg = (char *)pkt + 4;
+
+        first = tolower(*msg);
+        last = tolower(*(msg+7));
+
+        /*
+         * Errorck:
+         * - stop resending Error,
+         * - switch to state Initial
+         */
+        if (first == 'e' && last =='k') {
+            cancelTimer();
+            sentPacket = NULL;
+            nextState(Initial);
+        }
+    }
+    // Timer event triggered - this is Timer T2 to resend Error.
+    else if (event->type == Timer) {
+        if (!parent->sendPacketZRTP(sentPacket)) {
+            sendFailed();                 // returns to state Initial
+            return;
+        }
+        if (nextTimer(&T2) <= 0) {
+            timerFailed(SevereTooMuchRetries);     // returns to state Initial
+        }
+    }
+    else {  // unknown Event type for this state (covers Error and ZrtpClose)
+        if (event->type != ZrtpClose) {
+            parent->zrtpNegotiationFailed(Severe, SevereProtocolError);
+        }
+        sentPacket = NULL;
+        nextState(Initial);
+    }
+}
+
+void ZrtpStateClass::evSecureState(void) {
+
+    DEBUGOUT((cout << "Checking for match in SecureState.\n"));
+
+    char *msg, first, last;
+    uint8_t *pkt;
+
+    /*
+     * Handle a possible substate. If substate handling was ok just return.
+     */
+    if (secSubstate == WaitSasRelayAck) {
+        if (subEvWaitRelayAck())
+            return; 
+    }
+
+    if (event->type == ZrtpPacket) {
+        pkt = event->packet;
+        msg = (char *)pkt + 4;
+
+        first = tolower(*msg);
+        last = tolower(*(msg+7));
+
+        /*
+         * Confirm2:
+         * - resend Conf2Ack packet
+         * - stay in state
+         */
+        if (first == 'c' && last == '2') {
+            if (sentPacket != NULL && !parent->sendPacketZRTP(sentPacket)) {
+                sentPacket = NULL;
+                nextState(Initial);
+                parent->srtpSecretsOff(ForSender);
+                parent->srtpSecretsOff(ForReceiver);
+                parent->zrtpNegotiationFailed(Severe, SevereCannotSend);
+            }
+            return;
+        }
+        /*
+         * GoClear received, handle it. TODO fix go clear handling
+         */
+        if (first == 'g' && last == 'r') {
+            ZrtpPacketGoClear gpkt(pkt);
+            ZrtpPacketClearAck* clearAck = parent->prepareClearAck(&gpkt);
+
+            if (!parent->sendPacketZRTP(static_cast<ZrtpPacketBase *>(clearAck))) {
+                return;
+            }
+        // TODO Timeout to resend clear ack until user user confirmation
+        }
+    }
+    else {  // unknown Event type for this state (covers Error and ZrtpClose)
+        sentPacket = NULL;
+        parent->srtpSecretsOff(ForSender);
+        parent->srtpSecretsOff(ForReceiver);
+        nextState(Initial);
+        if (event->type != ZrtpClose) {
+            parent->zrtpNegotiationFailed(Severe, SevereProtocolError);
+        }
+        parent->sendInfo(Info, InfoSecureStateOff);
+    }
+}
+
+bool ZrtpStateClass::subEvWaitRelayAck() {
+    char *msg, first, last;
+    uint8_t* pkt;
+
+    /*
+     * First check the general event type, then discrimnate the real event.
+     */
+    if  (event->type == ZrtpPacket) {
+        pkt = event->packet;
+        msg = (char *)pkt + 4;
+
+        first = tolower(*msg);
+        last = tolower(*(msg+7));
+
+        /*
+         * SAS relayAck:
+         * - stop resending SASRelay,
+         * - switch to secure substate Normal
+         */
+        if (first == 'r' && last =='k') {
+            cancelTimer();
+            secSubstate = Normal;
+            sentPacket = NULL;
+        }
+        return true;
+    }
+    // Timer event triggered - this is Timer T2 to resend Error.
+    else if (event->type == Timer) {
+        if (!parent->sendPacketZRTP(sentPacket)) {
+            sendFailed(); // returns to state Initial
+            return false;
+        }
+        if (nextTimer(&T2) <= 0) {
+            // returns to state initial
+            // timerFailed(ZrtpCodes.SevereCodes.SevereTooMuchRetries);
+            return false;
+        }
+        return true;
+    }
+    return false;
+}
+
+int32_t ZrtpStateClass::startTimer(zrtpTimer_t *t) {
+
+    t->time = t->start;
+    t->counter = 0;
+    return parent->activateTimer(t->time);
+}
+
+int32_t ZrtpStateClass::nextTimer(zrtpTimer_t *t) {
+
+    t->time += t->time;
+    t->time = (t->time > t->capping)? t->capping : t->time;
+    t->counter++;
+    if (t->counter > t->maxResend) {
+        return -1;
+    }
+    return parent->activateTimer(t->time);
+}
+
+void ZrtpStateClass::sendErrorPacket(uint32_t errorCode) {
+    cancelTimer();
+
+    ZrtpPacketError* err = parent->prepareError(errorCode);
+    parent->zrtpNegotiationFailed(ZrtpError, errorCode);
+
+    sentPacket =  static_cast<ZrtpPacketBase *>(err);
+    nextState(WaitErrorAck);
+    if (!parent->sendPacketZRTP(static_cast<ZrtpPacketBase *>(err)) || (startTimer(&T2) <= 0)) {
+        sendFailed();
+    }
+}
+
+void ZrtpStateClass::sendSASRelay(ZrtpPacketSASrelay* relay) {
+    cancelTimer();
+    sentPacket = static_cast<ZrtpPacketBase *>(relay);
+    secSubstate = WaitSasRelayAck;
+    if (!parent->sendPacketZRTP(static_cast<ZrtpPacketBase *>(relay)) || (startTimer(&T2) <= 0)) {
+        sendFailed();
+    }
+}
+
+void ZrtpStateClass::sendFailed() {
+    sentPacket = NULL;
+    nextState(Initial);
+    parent->zrtpNegotiationFailed(Severe, SevereCannotSend);
+}
+
+void ZrtpStateClass::timerFailed(int32_t subCode) {
+    sentPacket = NULL;
+    nextState(Initial);
+    parent->zrtpNegotiationFailed(Severe, subCode);
+}
+
+void ZrtpStateClass::setMultiStream(bool multi) {
+    multiStream = multi;
+}
+
+bool ZrtpStateClass::isMultiStream() {
+    return multiStream;
+}
+
+/** EMACS **
+ * Local variables:
+ * mode: c++
+ * c-default-style: ellemtel
+ * c-basic-offset: 4
+ * End:
+ */