Example #1
0
        public static AmiMessage FromBytes(Byte[] bytes)
        {
            var result = new AmiMessage();

            for (var nrLine = 1;; nrLine++)
            {
                var crlfPos = bytes.Find(AmiMessage.TerminatorBytes, 0, bytes.Length);

                if (crlfPos == -1)
                {
                    throw new ArgumentException($"unexpected end of message after {nrLine} line(s)", nameof(bytes));
                }

                var line = Encoding.UTF8.GetString(bytes.Slice(0, crlfPos));
                bytes = bytes.Slice(crlfPos + AmiMessage.TerminatorBytes.Length);

                if (line.Equals(String.Empty))
                {
                    break;                     // empty line terminates
                }

                var kvp = line.Split(new[] { ':' }, 2);

                if (kvp.Length != 2)
                {
                    throw new ArgumentException($"malformed field on line {nrLine}", nameof(bytes));
                }

                result.Add(kvp[0], kvp[1]);
            }

            return(result);
        }
        public async Task <AmiMessage> Publish(AmiMessage action)
        {
            try
            {
                var tcs = new TaskCompletionSource <AmiMessage>(TaskCreationOptions.AttachedToParent);

                Debug.Assert(this.inFlight.TryAdd(action["ActionID"], tcs));

                var buffer = action.ToBytes();

                lock (this.writerLock) this.stream.Write(buffer, 0, buffer.Length);

                this.DataSent?.Invoke(this, new DataEventArgs(action.ToString()));

                var response = await tcs.Task;

                Debug.Assert(this.inFlight.TryRemove(response["ActionID"], out _));

                return(response);
            }
            catch (Exception ex)
            {
                this.Dispatch(ex);

                Debug.Assert(this.inFlight.TryRemove(action["ActionID"], out _));

                return(null);
            }
        }
Example #3
0
        public static AmiMessage FromBytes(Byte[] bytes)
        {
            var result = new AmiMessage();

            var stream = new MemoryStream(bytes);

            var reader = new StreamReader(stream, new UTF8Encoding(false));

            for (var nrLine = 1; ; nrLine++)
            {
                var line = reader.ReadLine();

                if (line == null)
                {
                    throw new ArgumentException("unterminated message", nameof(bytes));
                }

                if (line.Equals(String.Empty))
                {
                    break; // empty line terminates
                }

                var kvp = line.Split(new[] { ':' }, 2);

                if (kvp.Length != 2)
                {
                    throw new ArgumentException($"malformed field on line {nrLine}", nameof(bytes));
                }

                result.Add(kvp[0], kvp[1]);
            }

            return(result);
        }
Example #4
0
        public async Task <Boolean> Logoff()
        {
            AmiMessage request, response;

            request = new AmiMessage
            {
                { "Action", "Logoff" },
            };

            response = await this.Publish(request);

            return((response["Response"] ?? String.Empty).Equals("Goodbye", StringComparison.OrdinalIgnoreCase));
        }
Example #5
0
        public static AmiMessage FromString(String @string)
        {
            var bytes = Encoding.UTF8.GetBytes(@string);

            return(AmiMessage.FromBytes(bytes));
        }
Example #6
0
        public async Task <Boolean> Login(String username, String secret, Boolean md5 = true)
        {
            if (username == null)
            {
                throw new ArgumentNullException(nameof(username));
            }

            if (secret == null)
            {
                throw new ArgumentNullException(nameof(secret));
            }

            AmiMessage request, response;

            if (md5)
            {
                request = new AmiMessage
                {
                    { "Action", "Challenge" },
                    { "AuthType", "MD5" },
                };

                response = await this.Publish(request);

                if (!(response["Response"] ?? String.Empty).Equals("Success", StringComparison.OrdinalIgnoreCase))
                {
                    return(false);
                }

                var challengeResponse = MD5.Create()
                                        .ComputeHash(Encoding.ASCII.GetBytes(response["Challenge"] + secret));

                var key = "";

                for (var i = 0; i < challengeResponse.Length; i++)
                {
                    key += challengeResponse[i].ToString("x2");
                }

                request = new AmiMessage
                {
                    { "Action", "Login" },
                    { "AuthType", "MD5" },
                    { "Username", username },
                    { "Key", key },
                };

                response = await this.Publish(request);
            }
            else
            {
                request = new AmiMessage
                {
                    { "Action", "Login" },
                    { "Username", username },
                    { "Secret", secret },
                };

                response = await this.Publish(request);
            }

            return((response["Response"] ?? String.Empty).Equals("Success", StringComparison.OrdinalIgnoreCase));
        }
        private void WorkerMain()
        {
            try
            {
                this.processing = true;

                var reader = new StreamReader(this.stream, new UTF8Encoding(false));

                if (this.processing && this.stream != null && this.stream.CanRead)
                {
                    var line = reader.ReadLine();

                    this.DataReceived?.Invoke(this, new DataEventArgs(line + "\r\n"));

                    if (!line.StartsWith("Asterisk Call Manager", StringComparison.OrdinalIgnoreCase))
                    {
                        throw new Exception("this does not appear to be an Asterisk server");
                    }
                }

                var lines = new List <String>();

                while (this.processing && this.stream != null && this.stream.CanRead)
                {
                    lines.Add(reader.ReadLine());

                    if (lines.Last() != String.Empty)
                    {
                        continue;
                    }

                    this.DataReceived?.Invoke(this, new DataEventArgs(String.Join("\r\n", lines) + "\r\n"));

                    var message = new AmiMessage();

                    foreach (var line in lines.Where(line => line != String.Empty))
                    {
                        var kv = line.Split(new[] { ':' }, 2);

                        Debug.Assert(kv.Length == 2);

                        message.Add(kv[0], kv[1]);
                    }

                    if (message["Response"] != null && this.inFlight.TryGetValue(message["ActionID"], out var tcs))
                    {
                        Debug.Assert(tcs.TrySetResult(message));
                    }
                    else
                    {
                        this.Dispatch(message);
                    }

                    lines.Clear();
                }
            }
            catch (ThreadAbortException)
            {
                Thread.ResetAbort();
            }
            catch (Exception ex)
            {
                this.Dispatch(ex);
            }
        }