237 lines
4.7 KiB
C
237 lines
4.7 KiB
C
/*
|
|
Copyright (C) 2009 - 2010
|
|
|
|
Artem Makhutov <artem@makhutov.org>
|
|
http://www.makhutov.org
|
|
|
|
Dmitry Vagin <dmitry2004@yandex.ru>
|
|
|
|
Copyright (C) 2010 - 2011
|
|
bg <bg_one@mail.ru>
|
|
*/
|
|
#ifndef _GNU_SOURCE
|
|
#define _GNU_SOURCE /* vasprintf() in asterisk/utils.h */
|
|
#endif /* #ifndef _GNU_SOURCE */
|
|
|
|
#include "ast_config.h"
|
|
|
|
#include <sys/types.h>
|
|
#include <errno.h>
|
|
|
|
#include <asterisk/channel.h> /* ast_waitfor_n_fd() */
|
|
#include <asterisk/logger.h> /* ast_debug() */
|
|
|
|
#include "chan_dongle.h"
|
|
#include "at_read.h"
|
|
#include "ringbuffer.h"
|
|
|
|
|
|
/*!
|
|
* \brief Wait for activity on an socket
|
|
* \param fd -- file descriptor
|
|
* \param ms -- pointer to an int containing a timeout in ms
|
|
* \return 0 on timeout and the socket fd (non-zero) otherwise
|
|
* \retval 0 timeout
|
|
*/
|
|
|
|
EXPORT_DEF int at_wait (int fd, int* ms)
|
|
{
|
|
int exception, outfd;
|
|
|
|
outfd = ast_waitfor_n_fd (&fd, 1, ms, &exception);
|
|
|
|
if (outfd < 0)
|
|
{
|
|
outfd = 0;
|
|
}
|
|
|
|
return outfd;
|
|
}
|
|
|
|
#/* return number of bytes read */
|
|
EXPORT_DEF ssize_t at_read (int fd, const char * dev, struct ringbuffer* rb)
|
|
{
|
|
struct iovec iov[2];
|
|
int iovcnt;
|
|
ssize_t n = -1;
|
|
|
|
/* TODO: read until major error */
|
|
iovcnt = rb_write_iov (rb, iov);
|
|
|
|
if (iovcnt > 0)
|
|
{
|
|
n = readv (fd, iov, iovcnt);
|
|
|
|
if (n < 0)
|
|
{
|
|
if (errno != EINTR && errno != EAGAIN)
|
|
{
|
|
ast_debug (1, "[%s] readv() error: %d\n", dev, errno);
|
|
return n;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
else if (n > 0)
|
|
{
|
|
rb_write_upd (rb, n);
|
|
|
|
ast_debug (5, "[%s] receive %zu byte, used %zu, free %zu, read %zu, write %zu\n",
|
|
dev, n, rb_used (rb), rb_free (rb), rb->read, rb->write);
|
|
|
|
iovcnt = rb_read_all_iov (rb, iov);
|
|
|
|
if (iovcnt > 0)
|
|
{
|
|
if (iovcnt == 2)
|
|
{
|
|
ast_debug (5, "[%s] [%.*s%.*s]\n", dev,
|
|
(int) iov[0].iov_len, (char*) iov[0].iov_base,
|
|
(int) iov[1].iov_len, (char*) iov[1].iov_base);
|
|
}
|
|
else
|
|
{
|
|
ast_debug (5, "[%s] [%.*s]\n", dev,
|
|
(int) iov[0].iov_len, (char*) iov[0].iov_base);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
else
|
|
ast_log (LOG_ERROR, "[%s] at cmd receive buffer overflow\n", dev);
|
|
return n;
|
|
}
|
|
|
|
EXPORT_DEF int at_read_result_iov (const char * dev, int * read_result, struct ringbuffer* rb, struct iovec iov[2])
|
|
{
|
|
int iovcnt = 0;
|
|
int res;
|
|
size_t s;
|
|
|
|
s = rb_used (rb);
|
|
if (s > 0)
|
|
{
|
|
/* ast_debug (5, "[%s] d_read_result %d len %d input [%.*s]\n", dev, *read_result, s, MIN(s, rb->size - rb->read), (char*)rb->buffer + rb->read);
|
|
*/
|
|
|
|
if (*read_result == 0)
|
|
{
|
|
res = rb_memcmp (rb, "\r\n", 2);
|
|
if (res == 0)
|
|
{
|
|
rb_read_upd (rb, 2);
|
|
*read_result = 1;
|
|
|
|
return at_read_result_iov (dev, read_result, rb, iov);
|
|
}
|
|
else if (res > 0)
|
|
{
|
|
if (rb_memcmp (rb, "\n", 1) == 0)
|
|
{
|
|
ast_debug (5, "[%s] multiline response\n", dev);
|
|
rb_read_upd (rb, 1);
|
|
|
|
return at_read_result_iov (dev, read_result, rb, iov);
|
|
}
|
|
|
|
if (rb_read_until_char_iov (rb, iov, '\r') > 0)
|
|
{
|
|
s = iov[0].iov_len + iov[1].iov_len + 1;
|
|
}
|
|
|
|
rb_read_upd (rb, s);
|
|
|
|
return at_read_result_iov (dev, read_result, rb, iov);
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
else
|
|
{
|
|
if (rb_memcmp (rb, "+CSSI:", 6) == 0)
|
|
{
|
|
iovcnt = rb_read_n_iov (rb, iov, 8);
|
|
if (iovcnt > 0)
|
|
{
|
|
*read_result = 0;
|
|
}
|
|
|
|
return iovcnt;
|
|
}
|
|
else if (rb_memcmp (rb, "\r\n+CSSU:", 8) == 0 || rb_memcmp (rb, "\r\n+CMS ERROR:", 13) == 0 || rb_memcmp (rb, "\r\n+CMGS:", 8) == 0)
|
|
{
|
|
rb_read_upd (rb, 2);
|
|
return at_read_result_iov (dev, read_result, rb, iov);
|
|
}
|
|
else if (rb_memcmp (rb, "> ", 2) == 0)
|
|
{
|
|
*read_result = 0;
|
|
return rb_read_n_iov (rb, iov, 2);
|
|
}
|
|
else if (rb_memcmp (rb, "+CMGR:", 6) == 0 || rb_memcmp (rb, "+CNUM:", 6) == 0 || rb_memcmp (rb, "ERROR+CNUM:", 11) == 0 || rb_memcmp (rb, "+CLCC:", 6) == 0)
|
|
{
|
|
iovcnt = rb_read_until_mem_iov (rb, iov, "\n\r\nOK\r\n", 7);
|
|
if (iovcnt > 0)
|
|
{
|
|
*read_result = 0;
|
|
}
|
|
|
|
return iovcnt;
|
|
}
|
|
else
|
|
{
|
|
iovcnt = rb_read_until_mem_iov (rb, iov, "\r\n", 2);
|
|
if (iovcnt > 0)
|
|
{
|
|
*read_result = 0;
|
|
s = iov[0].iov_len + iov[1].iov_len + 1;
|
|
|
|
return rb_read_n_iov (rb, iov, s);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
EXPORT_DEF at_res_t at_read_result_classification (struct ringbuffer * rb, size_t len)
|
|
{
|
|
at_res_t at_res = RES_UNKNOWN;
|
|
unsigned idx;
|
|
|
|
for(idx = at_responses.ids_first; idx < at_responses.ids; idx++)
|
|
{
|
|
if (rb_memcmp (rb, at_responses.responses[idx].id, at_responses.responses[idx].idlen) == 0)
|
|
{
|
|
at_res = at_responses.responses[idx].res;
|
|
break;
|
|
}
|
|
}
|
|
|
|
switch (at_res)
|
|
{
|
|
case RES_SMS_PROMPT:
|
|
len = 2;
|
|
break;
|
|
|
|
case RES_CMGR:
|
|
len += 7;
|
|
break;
|
|
|
|
case RES_CSSI:
|
|
len = 8;
|
|
break;
|
|
default:
|
|
len += 1;
|
|
break;
|
|
}
|
|
|
|
rb_read_upd (rb, len);
|
|
|
|
/* ast_debug (5, "receive result '%s'\n", at_res2str (at_res));
|
|
*/
|
|
|
|
return at_res;
|
|
}
|