public string SendMessage(MORZEMessage msg, IMORZEContact to)
        {
            string err = null;

            if (to.isHasConfirmEtx() == true)
            {
                try
                {
                    ExtKey           ext;
                    byte []          netmsg = to.getMORZENetMessage(msg, out ext);
                    MORZESendMessage m      = new MORZESendMessage();
                    m.AddMessageBody(netmsg, ext.HashID, ext.Ext);
                    m.Send(m_netStream);
                    msg.Status = MORZEMessageStatus.sended;
                    msg.AddHashInfo(ext.HashID, SMSCrypt.CalcHash(ext.HashID, netmsg));
                }
                catch (Exception exp)
                {
                    OnConnectChange(false, exp.Message);
                }
            }
            else
            {
                SendInitialMessage(to);
            }
            return(err);
        }
        /// <summary>
        /// message send
        /// </summary>
        /// <param name="msg">mesage's plain text</param>
        /// <param name="to">reciver</param>
        /// <returns>error description</returns>
        public string SendMessage(string msg, IMORZEContact to)
        {
            string err = null;

            if (to.isHasConfirmEtx() == false)
            {
                try
                {
                    SendInitialMessage(to);

                    MORZEMessages msgs;
                    msgs = m_account.GetMessages(to);
                    if (msgs != null)
                    {
                        msgs.AddUnsendedNewMessages(msg);
                    }
                }
                catch (Exception exp)
                {
                    OnConnectChange(false, exp.Message);
                }
            }
            else
            {
                ExtKey       ext;
                MORZEMessage mmsg   = new MORZEMessage(msg.ToString());
                byte[]       netmsg = to.getMORZENetMessage(mmsg, out ext);

                MORZESendMessage m = new MORZESendMessage();
                m.AddMessageBody(netmsg, ext.HashID, ext.Ext);

                m.Send(m_netStream);

                MORZEMessages msgs;
                msgs = m_account.GetMessages(to);
                if (msgs != null)
                {
                    mmsg.AddHashInfo(ext.HashID, SMSCrypt.CalcHash(ext.HashID, netmsg));
                    msgs.AddSendedNewMessages(mmsg);
                }
            }
            return(err);
        }
        bool operateAsyncType1(byte[] data, byte[] tail)
        {
            bool isSuccess = false;
            int  off       = 1;

            byte[]      ext    = null;
            byte[]      sync   = null;
            byte[]      iv     = null;
            SMSHash     hashid = SMSHash.None;
            SMSSyncAlgo syncid = SMSSyncAlgo.None;

            int extlen = 0;
            int synlen = 0;

            switch (data[off])
            {
            case 1:    //MD5
                extlen = 0x10;
                hashid = SMSHash.MD5;

                break;
            }

            if (extlen > 0)
            {
                off++;
                ext = new byte[extlen];
                Array.Copy(data, off, ext, 0, ext.Length);
                off += ext.Length;
            }

            if (hashid != SMSHash.None)
            {
                switch (data[off])
                {
                case 1:    //DES
                    syncid = SMSSyncAlgo.DES;
                    synlen = 8;
                    break;
                }
            }
            if (synlen > 0)
            {
                off++;
                sync = new byte[synlen];
                iv   = new byte[synlen];
                Array.Copy(data, off, sync, 0, sync.Length);
                off += sync.Length;
                Array.Copy(data, off, iv, 0, iv.Length);
                off += iv.Length;
            }
            if (off + 2 == data.Length) // +2  - CRC16
            {
                byte[] contactaddres;
                string cont = null;
                if (string.IsNullOrEmpty(SMSCrypt.SyncDecode(syncid, tail, sync, iv, out contactaddres)) == false)
                {
                    contactaddres = null;
                }
                if (contactaddres != null)
                {
                    try
                    {
                        cont = Encoding.ASCII.GetString(contactaddres);
                        Convert.FromBase64String(cont.Substring(4));
                        isSuccess = m_acc.updateSynKey(hashid, ext, syncid, sync, iv, cont);
                    }
                    catch
                    {
                        isSuccess = false;
                    }
                }
            }
            if (isSuccess == true)
            {
                MORZESendMessage cmdMsgTyp2;

                //---------------
                cmdMsgTyp2 = new MORZESendMessage();

                BufferBuilder bb = new BufferBuilder();
                bb.AddByte(2); // Type 2 - уведомление о получении ключей
                bb.AddByte((byte)hashid);
                bb.AddBytes(SMSCrypt.CalcHash(hashid, sync));

                //byte[] msg = bb.GetAllBytes();
                //bb = new BufferBuilder();
                //bb.AddByte((byte)((int)0x80 ^ (int)hashid));
                //bb.AddBytes(SMSCrypt.CalcHash(hashid, msg));
                //bb.AddBytes(ext);
                //bb.AddBytes(msg);
                //cmdMsgTyp2.WriteBytes(bb.GetAllBytes());
                byte[] res;
                if (string.IsNullOrEmpty(SMSCrypt.SyncEncode(syncid, bb.GetAllBytes(), sync, iv, out res)) == true)
                {//send notify to client
                    cmdMsgTyp2.AddMessageBody(res, hashid, ext);
                    if (m_responses == null)
                    {
                        m_responses = new List <SMSSendCommand>();
                    }

                    //set server filter setting
                    SMSSendExt setext = new SMSSendExt();
                    setext.pushExt(hashid, ext);
                    m_responses.Add(setext);
                    m_responses.Add(cmdMsgTyp2);
                }
                else
                {
                    isSuccess = false;
                }
            }
            return(isSuccess);
        }
        public MORZERecvMessages(IMORZEAccount acc, byte[] data) : base(data)
        {
            int off = 0;

            byte[] msg;

            byte[] hash;
            byte[] ext;

            m_responses = null;
            byte[] addascii = Encoding.ASCII.GetBytes(acc.GetMyAccount());

            m_acc = acc;
            bool    err     = false;
            SMSHash mrzhash = SMSHash.None;

            while (off < data.Length && err == false)
            {
                msg  = null;
                hash = null;
                ext  = null;

                off++;             //ttl
                ushort msglen = 0;
                switch (data[off]) //hash
                {
                case 0x01:         //md5
                    hash    = new byte[0x10];
                    mrzhash = SMSHash.MD5;
                    break;

                case 0x81:
                    hash    = new byte[0x10];
                    mrzhash = SMSHash.MD5;
                    ext     = new byte[0x10];
                    break;

                default:
                    err = true;
                    break;
                }
                if (err == false)
                {
                    off++;
                    Array.Copy(data, off, hash, 0, hash.Length);
                    off += hash.Length;
                    if (ext != null)
                    {
                        Array.Copy(data, off, ext, 0, ext.Length);
                        off += ext.Length;
                    }
                    msglen = BitConverter.ToUInt16(data, off);
                    off   += 2;
                    if (msglen + off <= data.Length)
                    {
                        msg = new byte[msglen];
                        Array.Copy(data, off, msg, 0, msg.Length);
                        off += msg.Length;
                    }
                    else
                    {
                        err = true;
                    }
                }
                if (err == false)
                {
                    bool add = false;
                    if (checkHash(mrzhash, hash, msg) == true)
                    {
                        if (ext == null)
                        {//данные зашифрованные открытым ключем
                            byte   asynclen = 0;
                            byte[] smsg     = null;
                            byte[] async    = null;
                            asynclen = (byte)((int)addascii[0x10] ^ (int)msg[0]);
                            if (asynclen > 0)
                            {
                                async = new byte[asynclen];
                                Array.Copy(msg, 1, async, 0, async.Length);
                                if ((int)asynclen < msg.Length)
                                {
                                    smsg = new byte[msg.Length - (1 + asynclen)];
                                    Array.Copy(msg, 1 + asynclen, smsg, 0, smsg.Length);
                                }
                                else
                                {
                                    if (msg.Length < asynclen)
                                    {
                                        err = true;
                                    }
                                }
                                if (err == false)
                                {
                                    byte[] dec;
                                    byte[] tail       = null;
                                    int    taillength = msg.Length - asynclen - 1;
                                    if (taillength < 0)
                                    {
                                        err = true;
                                    }
                                    else
                                    {
                                        tail = new byte[taillength];
                                        Array.Copy(msg, async.Length + 1, tail, 0, taillength);
                                        if (acc.decodeAsync(async, out dec) == true)
                                        {
                                            err = !operateAsync(dec, tail);
                                        }
                                    }
                                }
                            }
                            else
                            {
                                err = true;
                            }
                        }
                        else
                        {
                            add = true;
                        }

                        if (add == true)
                        {
                            if (m_msgData == null)
                            {
                                m_msgData = new List <byte[]>();
                            }
                            if (m_msgHash == null)
                            {
                                m_msgHash = new List <byte[]>();
                            }
                            if (m_msgExt == null)
                            {
                                m_msgExt = new List <byte[]>();
                            }
                            m_msgData.Add(msg);
                            m_msgHash.Add(hash);
                            m_msgExt.Add(ext);

                            IMORZEContact mc = m_acc.GetAddressBook().GetContact(ext);

                            if (mc != null)
                            {
                                if (mc.PutReciveMessage(msg, hash, mrzhash, ext) == true)
                                {
                                    MORZEContact cc = mc as MORZEContact;
                                    if (cc != null)
                                    {
                                        List <byte[]> r = cc.Responses;
                                        if (r != null)
                                        {
                                            foreach (byte[] i in r)
                                            {
                                                MORZESendMessage cmdMsgTyp2 = new MORZESendMessage();
                                                cmdMsgTyp2.AddMessageBody(i, mrzhash, ext);
                                                if (m_responses == null)
                                                {
                                                    m_responses = new List <SMSSendCommand>();
                                                }
                                                m_responses.Add(cmdMsgTyp2);
                                            }
                                            cc.Responses.Clear();
                                        }
                                    }
                                }
                            }
                        }
                    } //if (checkHash(mrzhash, hash, msg) == true)
                }
            }         //while (off<data.Length && err==false)
            if (err == true || off != data.Length)
            {
                m_msgData = null;
                m_msgHash = null;
                m_msgExt  = null;
            }
        }