Friday, December 11, 2015

Block aggressive advertising calls

In my country, but I bet anywhere else do the same, the telephone calls for proposing new products are constantly increasing, these annoying calls, sometimes malicious, aren't always welcome.

My country has adopted a kind of institutional way to handle this phenomena, it is called  "registro pubblico delle opposizioni", using this, any citizen may publish his telephone number, merely this action should him guarantee he would never ever receive again any advertisement call.

Unfortunately, reality can't be more distant from what really is going to happen.

Telephone spammers do not use to follow rules, and the weak statement "this user does not want to be called for commercial purposes "  is not enough to prevent they to call you. 

If you do not want to be called, you have to find yourself a way to do that.
In other words, you have to find a way to recognize them as spammer, and forward them, for example, to an announce stating you do not want to be called.

As an Asterisk user I have a framework at my disposal, which potentially lets me route calls using any sort of policy; but the main issue is how to identify a spammer?

Internet community, seems to have faced this problem and has built a kind of database in which people complaints about telephone numbers.

It exists, for example, a service called TELLOWS on which anyone can leave a comment on a source telephone number.

So why don't use those information to identify spammers and avoid unwanted telephone calls?

My proposal is integrate the service provided by TELLOWS in the Asterisk dialplan.

Here an example of my thougths.

in the Asterisk dialplan
exten =>  incoming,       1,              Noop(Incoming call is just arrived)
exten =>  incoming,       n,              Set(tellowsc=${SHELL(tellows_c.sh ${CALLERID(num)})})
exten =>  incoming,       n,              GotoIf($[${tellowsc}>1]?reject)
exten =>  incoming,       n,              Dial(${destination},30,${FLAGS})
exten =>  incoming,       n,              HangUP()
exten =>  incoming,       n(reject),      Answer()
exten =>  incoming,       n,              Wait(2)
exten =>  incoming,       n,              Set(CDR(userfield)=RejectedByPolicy)
exten =>  incoming,       n,              Playback(spam)
exten =>  incoming,       n,              HangUP()
the bash script for the italian version of TELLOWS
#!/bin/sh
score=$(wget -O - -q "http://www.tellows.it/num/$1" | grep "/images/score/score[0-9].png" | grep scoreimage | sed -r 's/.*score([0-9])\.png.*/\1/');
comments=$(wget -O - -q "http://www.tellows.it/num/$1" | grep "itemprop" | grep "Numero di commenti:"| sed -r 's/.*>([0-9]+)<.*/\1/');
echo -n "$comments";
I used, to reject calls, the number of comments the number has, but there's also a kind of number score, you can use to take your decision




Thursday, October 22, 2015

JabberSend crashes your system if it has no connection with the XMPP server.

JabberSend is quite a useful function.
It lets you send xmpp instant messages, and it can be used for various things such as alert you when a call hits your voice mail or also that someone is calling you.

Here an example dial plan.
[outside_line]
exten =>  s, 1,  Noop(Incoming call is just arrived)
exten =>  s, n,  JabberSend(XMPP_Account,Jid@domain,Incoming call from "${CALLERID(num)}")
exten =>  s, n,  Dial(${GLOBAL(incoming_call_group)},30,${FLAGS_incoming})
exten =>  s, n,  JabberSend(XMPP_Account,Jid@domain,${CALLERID(num)} is leaving VM message)
exten =>  s, n,  VoiceMail(${GLOBAL(incoming_voicemail)}@asterisk)
exten =>  s, n,  Hangup()


Nice feature, but it comes with a big problem: if for any reason the XMPP connection is down, JabberSend crashes your Asterisk system.
This kind of behaviour is obviously not admittable in any kind of production environment.

You can however use it in a production environment making a slight modification to the code source code of res_xmpp.c

In the Asterisk version I'm using, the 11.6, modifying the function xmpp_client_send_message as follow, the result is:
if JabberSend is invoked and there's no connection to the xmpp server it logs a warning message instead of crashing the system.

here the code, the red indicates where I modified the original code:
static int xmpp_client_send_message(struct ast_xmpp_client *client, int group, const char *nick, const char *address, const char *message)
{
        RAII_VAR(struct xmpp_config *, cfg, ao2_global_obj_ref(globals), ao2_cleanup);
        RAII_VAR(struct ast_xmpp_client_config *, clientcfg, NULL, ao2_cleanup);
        int res = 0;
        char from[XMPP_MAX_JIDLEN];
        iks *message_packet;

        if (!cfg || !cfg->clients || !(clientcfg = xmpp_config_find(cfg->clients, client->name)) ||
            !(message_packet = iks_make_msg(group ? IKS_TYPE_GROUPCHAT : IKS_TYPE_CHAT, address, message))) {
                return -1;
        }

        if (!ast_strlen_zero(nick) && ast_test_flag(&clientcfg->flags, XMPP_COMPONENT)) {
                snprintf(from, sizeof(from), "%s@%s/%s", nick, client->jid->full, nick);
        } else {
                snprintf(from, sizeof(from), "%s", client->jid->full);
        }

        iks_insert_attrib(message_packet, "from", from);

        //begin//
        if (client->state == XMPP_STATE_CONNECTED) {
                                                    res = ast_xmpp_client_send(client, message_packet);
                                                   }
                                              else {
                                                    res = -1;
                                                    ast_log(LOG_WARNING, "XMPP: Not connected, unable to send messages to %s\n", client->name);
                                                   }
        //end//


        iks_delete(message_packet);

        return res;
}
I hope this can help.

Sunday, May 24, 2015

Access your PBX using voice channels

As VoIP PBX administrators, we often have to deal with uncooperative network administrators. IP PBXs rely on the underlying network infrastructure for both normal operation and remote access. However, they frequently encounter restrictive network policies, which can complicate remote management. It can be particularly frustrating when network administrators implement policies without consultation, often resulting in denied remote access for everyone except themselves. In such scenarios, even a simple task like renaming an extension (e.g., changing 400 to something else) can become time-consuming. You may need to visit the client’s location to make the change on-site. In the best-case scenario, you might ask the client to use a PC with software like TeamViewer, but this still adds unnecessary complexity. If you’ve faced similar challenges, you know how frustrating it can be.

In this article, I won’t claim to provide the ultimate solution, but I’ll share a method to mitigate the situation. It requires no additional hardware and no human assistance.

Do you remember the days of using analog modems to connect to the internet? At the time, affordable digital lines were unavailable, so modems were the only option. The solution I propose is to use voice lines—VoIP or otherwise—in a way similar to how modems were used back then.
  1. Linux Ham Radio AX25 software suite
  2. Alsa loopback device
  3. Asterisk Alsa channel
You might wonder: why use amateur radio software for this? There are several reasons. First, this software is mature, well-tested, and readily available. Additionally, old modems required a continuous carrier signal to maintain a connection. This could lead to latency issues over VoIP connections, similar to the problems you encounter with failed FAX transmissions. In contrast, amateur radio packet protocols only generate a carrier during actual data transmission, making them less susceptible to latency problems.
The final idea should look such as the following images:


This solution won’t provide the highest connection speeds for your Asterisk server. The maximum achievable speed with this method is 38,400 bps. However, it allows you to remotely manage your installation without relying on others for remote access!

The implementation

The Amateur Radio AX.25

To begin, ensure that the Ham Radio kernel modules are installed. You can verify their presence by checking for mkiss.ko in the /lib/modules/ directory, which indicates that the necessary modules are available.
A Note for Red Hat-Based Distributions
For Red Hat-derived distributions, such as Red Hat Enterprise Linux 5 and 6, as well as the corresponding CentOS versions and possibly others, the Ham Radio kernel modules are not built by default. In this case, you’ll need to build them manually.
For Red Hat users, the best approach is to download the kernel source using the yum utility. Then, integrate the missing Ham Radio kernel modules by transplanting them from the corresponding kernel sources available at www.kernel.org. (You can refer to guides on building kernel modules on CentOS systems after performing the transplant.)
Once your kernel setup is complete, you can turn your attention to the user-space utilities required for this task. Required User-Space Packages It’s recommended to build these utilities from source to ensure compatibility with your environment. Regardless of your approach, ensure you have the following packages installed:
  • ax25-apps
  • ax25-tools
  • libax25
  • soundmodem
The AX.25 protocol stack is relatively simple to configure. In my case, the only necessary change was adding a single line to the axports file located in the /etc/ax25 directory. The axports file defines port names and their associated mappings. Here’s an example entry:
sm0     HQH1            4800    255     2       Test connection
The fields in this file represent the following:
  • Port Name: The name of the new interface used to send packets through the voice link.
  • Callsign: The L2 address used by the AX.25 protocol. In amateur radio, this is assigned by an authority, but in our case, any identifier will work.
  • Speed: The communication speed between the TNC and the computer. In this setup, it refers to the communication speed between the kernel and the soundmodem (a software implementation of the TNC).
  • MTU: The Maximum Transmission Unit for the AX.25 connection.
  • AX.25 Window Parameter: This is equivalent to the "maxframe" setting.
  • Description: A description of the connection.
An example of its configuration is the following:
<?xml version="1.0"?>
<modem>
<configuration name="AX25">
<chaccess txdelay="150" slottime="100" ppersist="40" fulldup="1" txtail="100"/>
<audio type="alsa" device="plughw:Loopback,0,0" halfdup="0" capturechannelmode="Mono"/>
<ptt file="none" hamlib_model="" hamlib_params="" gpio="0"/>
<channel name="sm0">
<mod mode="fsk" bps="4800" f0="1200" f1="2200" diffenc="1" inlv="8" fec="1" tunelen="32" synclen="32" filter="df9ic/g3ruh"/>
<demod mode="fsk" bps="4800" f0="1200" f1="2200" diffdec="1" inlv="8" fec="3" mintune="16" minsync="16" filter="df9ic/g3ruh"/>

<pkt mode="MKISS" ifname="sm0" hwaddr="HQH1" ip="23.0.0.1" netmask="255.255.255.0" broadcast="23.0.0.255"
file="/dev/soundmodem0" unlink="1"/>
</channel>
</configuration>
</modem>

This setup has been proven to work, but it is slow—limited to 4,800 bps! If your voice path is clear, there is room to achieve higher speeds with adjustments. To simplify the explanation, I’ve divided the configuration into color-coded sections:
  • Orange: This section specifies the media access. I used some default settings, but keep in mind that the media we are working with is significantly different from what this protocol was originally designed for. Our media is full-duplex, so we don’t need to adhere to time constraints like time slots or transmission delays.
  • Magenta: This section defines the ALSA hardware we’ll use. I’ll explain this in more detail in the next section, "ALSA Loopback Device." For now, note that in this section, you must specify an ALSA aloop device channel, prefixed by "plug" to handle resampling issues.
  • Yellow: This section sets the channel parameters and binds the configuration to the Linux network interface—in this case, sm0.
  • Green: Here, you configure the modulation and demodulation method, throughput, and frequencies. Feel free to experiment with different combinations to find what works best in your specific environment.
  • Cyan: This section outlines the packet mode parameters. It assigns the Layer 2 and Layer 3 addresses for your connection.

Alsa loopback device aloop

The primary reason for using this piece of software is to interface Asterisk with the soundmodem device. Both Asterisk and the soundmodem rely on ALSA devices for input and output, making the ALSA loopback device the most natural way to connect them.
The aloop module is included in every Linux distribution I’m aware of, so finding one ready for use should not be an issue. In most cases, you simply need to load the aloop module into the kernel.
modprobe snd-aloop
This should result in 8 new channels ready to be used
 card 2: Loopback [Loopback], device 0: Loopback PCM [Loopback PCM]
  Subdevices: 8/8
  Subdevice #0: subdevice #0
  Subdevice #1: subdevice #1
  Subdevice #2: subdevice #2
  Subdevice #3: subdevice #3
  Subdevice #4: subdevice #4
  Subdevice #5: subdevice #5
  Subdevice #6: subdevice #6
  Subdevice #7: subdevice #7
card 2: Loopback [Loopback], device 1: Loopback PCM [Loopback PCM]
  Subdevices: 7/8
  Subdevice #0: subdevice #0
  Subdevice #1: subdevice #1
  Subdevice #2: subdevice #2
  Subdevice #3: subdevice #3
  Subdevice #4: subdevice #4
  Subdevice #5: subdevice #5
  Subdevice #6: subdevice #6
  Subdevice #7: subdevice #7
We only need one of the ALSA loopback channels, so you can adjust the module loading options by specifying parameters in your distribution's configuration file for kernel modules, such as modprobe.conf or its equivalent.

Asterisk

The Asterisk portion of the configuration utilizes the less commonly used chan_alsa module. The Asterisk ALSA channel driver was originally developed to allow the server console to function as an endpoint in the telephony system. As the name suggests, chan_alsa uses ALSA-compatible devices to manage the voice stream. To adapt this for our setup, the only modification needed in the default alsa.conf configuration is specifying the ALSA device to be used—specifically, the aloop device.
[general]
autoanswer=yes
context=local
extension=s
input_device=plughw:Loopback,1,0
output_device=plughw:Loopback,1,0

At this point, by directing a call to this endpoint, we have effectively created one leg of the tunnel. For example, in extensions.conf:
exten => 929,           1,              Dial(Console/snd/controlC0,30)

Note:
During actual tests of the tunnel, although AX.25 is treated as a type of Ethernet and implements an ARP-style Layer 2 address resolution, I had to set it manually.
If you encounter the same issue, the ARP syntax for AX.25 bindings is as follows:
arp -H ax25 -s 23.0.0.1 HQH1





Monday, February 16, 2015

Google Talk ends its services, now what?

Due to the decision Google made to turn off its xmpp service talk, I've been forced to migrate another xmpp service.
I thought it would be an easy task, just put new data into xmpp.conf and it's done. But it didn't go that way.
As soon as I run the new configuration, I got:

<--- XMPP sent to 'tigase.im' --->
<?xml version='1.0'?><stream:stream xmlns:stream='http://etherx.jabber.org/streams' xmlns='jabber:client' to='tigase.im' version='1.0'>
<------------->

<--- XMPP received from 'tigase.im' --->
<?xml version='1.0'?><stream:stream xmlns='jabber:client' xmlns:stream='http://etherx.jabber.org/streams' from='tigase.im' id='6be9205d-5793-4ae6-84e0-afd0983ed490' version='1.0' xml:lang='en'>
<------------->

<--- XMPP sent to 'tigase.im' --->
<starttls xmlns='urn:ietf:params:xml:ns:xmpp-tls'/>
<------------->

<--- XMPP received from 'tigase.im' --->
<stream:features><sm xmlns="urn:xmpp:sm:3"/><register xmlns="http://jabber.org/features/iq-register"/><mechanisms xmlns="urn:ietf:params:xml:ns:xmpp-sasl"/><ver xmlns="urn:xmpp:features:rosterver"/><starttls xmlns="urn:ietf:params:xml:ns:xmpp-tls"><required/></starttls><compression xmlns="http://jabber.org/features/compress"><method>zlib</method></compression></stream:features>
<------------->

<--- XMPP received from 'tigase.im' --->
<proceed xmlns="urn:ietf:params:xml:ns:xmpp-tls"/>
<------------->
[Feb 16 19:20:56] ERROR[20733]: res_xmpp.c:2558 xmpp_client_requested_tls: TLS connection for client 'tigase.im' cannot be established. OpenSSL initialization failed.
[Feb 16 19:20:56] WARNING[20733]: res_xmpp.c:3571 xmpp_client_receive: Parsing failure: Hook returned an error.
[Feb 16 19:20:56] WARNING[20733]: res_xmpp.c:3635 xmpp_client_thread: JABBER: socket read error

What the hell was there?
I reviewed all the res_xmpp parameters, but at last I had to accept to the fact it doesn't work.
A xmpp provider related issue?
Might be, but changing to another xmpp service didn't help, and connection kept fail.

Debug log states it is a TLS connection related problem...
I started my investigation on iksemel, the xmpp parser library.
It has its own tls mechanism based on gnutls, which is independent with the one implemented in res_xmpp, but at that time I didn't know yet.

There is a tool in the "tool" directory of the iksemel library which performs a simple xmpp connection.
It is the iksroster.
Using that to test the xmpp connection I got a TSL connection error.

Looking at the code, the I found in the src/stream.c file that function handshake performs the negotiation for the TLS connection:

static int handshake (struct stream_data *data)
{
        const int protocol_priority[] = { GNUTLS_TLS1, GNUTLS_SSL3, 0 };
        const int kx_priority[] = { GNUTLS_KX_RSA, 0 };
        const int cipher_priority[] = { GNUTLS_CIPHER_3DES_CBC, GNUTLS_CIPHER_ARCFOUR, 0};
        const int comp_priority[] = { GNUTLS_COMP_ZLIB, GNUTLS_COMP_NULL, 0 };
        const int mac_priority[] = { GNUTLS_MAC_SHA, GNUTLS_MAC_MD5, 0 };
        int ret;

        if (gnutls_global_init () != 0) return IKS_NOMEM;              
        if (gnutls_certificate_allocate_credentials (&data->cred) < 0) return IKS_NOMEM;       
        if (gnutls_init (&data->sess, GNUTLS_CLIENT) != 0) {
                                                            gnutls_certificate_free_credentials (data->cred);
                                                            return IKS_NOMEM;
                                                           }
        gnutls_protocol_set_priority (data->sess, protocol_priority);
        gnutls_cipher_set_priority(data->sess, cipher_priority);
        gnutls_compression_set_priority(data->sess, comp_priority);
        gnutls_kx_set_priority(data->sess, kx_priority);
        gnutls_mac_set_priority(data->sess, mac_priority);
        gnutls_credentials_set (data->sess, GNUTLS_CRD_CERTIFICATE, data->cred);

        gnutls_transport_set_push_function (data->sess, (gnutls_push_func) tls_push);
        gnutls_transport_set_pull_function (data->sess, (gnutls_pull_func) tls_pull);
        gnutls_transport_set_ptr (data->sess, data->prs);

        ret = gnutls_handshake (data->sess);
        if (ret != 0) {
                       gnutls_deinit (data->sess);
                       gnutls_certificate_free_credentials (data->cred);
                       return IKS_NET_TLSFAIL;
                      }
        data->flags &= (~SF_TRY_SECURE);
        data->flags |= SF_SECURE;
        iks_send_header (data->prs, data->server);
        return IKS_OK;
}

The code shows the function is using a deprecated chiper, it could be the reason why TLS connection fails.
A test that worth to try is add another more recent cipher.
const int cipher_priority[] = { GNUTLS_CIPHER_AES_256_CBC,GNUTLS_CIPHER_AES_128_CBC,GNUTLS_CIPHER_3DES_CBC, GNUTLS_CIPHER_ARCFOUR, 0};
Indeed The new version made the trick, and that time on, iksroster successfully connected to the server.
In the asterisk console however, no change.
Looking with attention to the res_xmpp.c code, I finally got the problem: asterisk does its own TLS connection using OpenSSL, and it is bound to use SSLv3.
You can be more lucky than me, but it seems not many xmpp servers are using SSLv3!
You can test yourself  you xmpp provider using the tools provided by https://xmpp.net/, in my case, tigase.im used TLSv1.2.
The only way I found to make my connection work has been patch my res_xmpp.c to use TLSv1.1

static int xmpp_client_requested_tls(struct ast_xmpp_client *client, struct ast_xmpp_client_config *cfg, int type, iks *node)
{
#ifdef HAVE_OPENSSL
        int sock;
#endif
        int dbg_info=0;

        if (!strcmp(iks_name(node), "success")) {
                /* TLS is up and working, we can move on to authenticating now */
                xmpp_client_change_state(client, XMPP_STATE_AUTHENTICATE);
                return 0;
        } else if (!strcmp(iks_name(node), "failure")) {
                /* TLS negotiation was a failure, close it on down! */
                return -1;
        } else if (strcmp(iks_name(node), "proceed")) {
                /* Ignore any other responses */
                return 0;
        }

#ifndef HAVE_OPENSSL
        ast_log(LOG_ERROR, "Somehow we managed to try to start TLS negotiation on client '%s' without OpenSSL support, disconnectin$
        return -1;
#else
//        client->ssl_method = SSLv3_method();  //this was the original
        client->ssl_method = TLSv1_1_method();
        if (!(client->ssl_context = SSL_CTX_new((SSL_METHOD *) client->ssl_method))) {
                dbg_info=1;
                goto failure;
        }

        if (!(client->ssl_session = SSL_new(client->ssl_context))) {
                dbg_info=2;
                goto failure;
        }

        sock = iks_fd(client->parser);
        if (!SSL_set_fd(client->ssl_session, sock)) {
                dbg_info=3;
                goto failure;
        }

        if (!SSL_connect(client->ssl_session)) {
                dbg_info=4;
                goto failure;
        }

Now my connection works.

I hope you find this useful.


Thursday, June 12, 2014

Asterisk ACD pause status BLF

Recently I installed for a customer an Asterisk PBX with ACD service.
This customer has the necessity to have two queues with specialized agents.
If situation requires, not specialized agent should answer the call.
In the situation in which only one specialized agent is logged in, and he/she is not at the phone, because whatever reason, it would happen that the call is not routed to other agent with lower priority.
To fix this scenario, you can use the autopause feature, which put in the pause status an agent if he/she does not answer the call.
But when the agent returns back at him/her position, he/she can not know he/she has been auto paused, and then he/she could sit and wait a call that will never arrive.
It would be nice to have a signal on the telephone stating the ACD pause status.

I do not find any built-in feature in the Asterisk I were using that let me do this, so I wrote a script to have such service.
The idea is to watch the "queue_log" where asterisk puts all events about ACD and agents.
When agent pause event appears in such log, you can set the respective devicestate using "devstate change" Asterisk cli command.

Here my script.

#!/bin/sh
#    Agentwatch 0.1 2014 Alessandro Carminati

on_die()
{
        rm /tmp/aw
        exit 0
}


trap 'on_die' TERM INT KILL

[ -f /tmp/aw ] && echo "aw exists, exit" && exit;
touch /tmp/aw

IFS=$'\n';
for i in $(rasterisk -x "queue show queue1" | grep "SIP"); do
    status="NOT_INUSE";
    echo $i |grep "paused" >/dev/null && status="INUSE";
    ext=$(echo $i | cut -d "(" -f1| sed -e 's/ //g'| sed -e 's/.*sip//');
    rasterisk -x "devstate change custom:queue1_${ext} ${status}" >/dev/null
    [ "${1}" = "-d" ] && echo "devstate change custom:queue1_${ext} ${status}"
    done
for i in $(rasterisk -x "queue show queue2" | grep "SIP"); do
    status="NOT_INUSE";
    echo $i |grep "paused" >/dev/null && status="INUSE";
    ext=$(echo $i | cut -d "(" -f1| sed -e 's/ //g'| sed -e 's/.*sip//');
    rasterisk -x "devstate change custom:queue2_${ext} ${status}" >/dev/null
    [ "${1}" = "-d" ] && echo "devstate change custom:queue2_${ext} ${status}"
    done

tail -n0 -f /var/log/asterisk/queue_log | while read LOGLINE
do
   if [[ "${LOGLINE}" == *"|PAUSE|"* ]]; then
                                             coda=$(echo "${LOGLINE}" | cut -d"|" -f3);
                                             agente=$(echo "${LOGLINE}" | cut -d"|" -f4|cut -d"p" -f2);
                                             [ "${1}" = "-d" ] && echo "l'agente $agente entra in pausa per la coda $coda";
                                             rasterisk -x "devstate change custom:${coda}_${agente} INUSE" >/dev/null
                                        fi
   if [[ "${LOGLINE}" == *"|UNPAUSE|"* ]]; then
                                             coda=$(echo "${LOGLINE}" | cut -d"|" -f3);
                                             agente=$(echo "${LOGLINE}" | cut -d"|" -f4|cut -d"p" -f2);
                                             [ "${1}" = "-d" ] && echo "l'agente $agente esce dalla pausa per la coda $coda";
                                             rasterisk -x "devstate change custom:${coda}_${agente} NOT_INUSE" >/dev/null
                                        fi

done



Because you want to see this on the phone, you have to define some hints so them can be configured as blf on the phone. (Agent extensions goes from 511 to 519).

exten => *9*511,             hint,   Custom:queue1_511&Custom:queue2_511
exten => *9*512,             hint,   Custom:queue1_512&Custom:queue2_512
exten => *9*513,             hint,   Custom:queue1_513&Custom:queue2_513
exten => *9*514,             hint,   Custom:queue1_514&Custom:queue2_514
exten => *9*515,             hint,   Custom:queue1_515&Custom:queue2_515
exten => *9*516,             hint,   Custom:queue1_516&Custom:queue2_516
exten => *9*517,             hint,   Custom:queue1_517&Custom:queue2_517
exten => *9*518,             hint,   Custom:queue1_518&Custom:queue2_518
exten => *9*519,             hint,   Custom:queue1_519&Custom:queue2_519


And at last, because you want this service starts automaticaly when server goes up, here is my redhat fashon rc script.

#!/bin/sh
# $Id: rc.redhat.agentwatch 268535 2010-06-06 05:31:11Z AC$
#
# AgentWatch    Starts, Stops and Reloads
#
# chkconfig: 2345 90 60
# description: Track using blf pause status
# processname: agentwatch
# pidfile: /var/run/aw.pid
#
. /etc/init.d/functions

if test -e /etc/sysconfig/mouse ; then
    . /etc/sysconfig/mouse
fi

RETVAL=0

start() {
        echo  "Starting AgentWatch service: "
        /usr/aw/agentwatch.sh >/dev/null &
        echo $! > /var/run/aw.pid
        }

stop() {
        echo  "Shutting down AgentWatch service: "
        kill -9 $(cat /var/run/aw.pid);
       }

case "$1" in
  start)
        start
        ;;
  stop)
        stop
        ;;
  restart|reload)
        stop
        start
        ;;
  *)
        echo $"Usage: $0 {start|stop|restart}"
        exit 1
esac

exit $RETVAL

Any comment about this argument is very welcome.

Sunday, May 18, 2014

Asterisk and old Pay Phones

Today I want to talk you about a matter I have with an old Pay phone.
The less young among my readers may recall the old days when there was no mobile phone.
Those days if it happened you had to call someone, you used to go to a payphone booth and call.
During the 70s and early 80s in some Europeans countries among others, there were widespread usage of some special coins, telephone tokens. Those times, if you wanted to use one of those payphone, you also needed a telephone token.

Today's topic however, is not properly the payphone, it is instead the way old Pay Phones collect tokens, or to say it better how to reproduce it in a modern Asterisk based telephone system.
For today topic I focused on the only Pay Phone I have, the Italian U+I.

U+I stands for "urbane ed interurbane" (local calls and long distance call), is the first public phone in Italy by which you could call someone outside of your city without operator's support.
At that times, the signaling between central office and telephones was quite easy, they had only a twisted pair and quite simple technology. The signaling was done just by reversing polarity of the twisted pair.
Signals from central office side was something like

Duration meaning
>250ms end call
~50ms collect token
Continuous out of order

Also, from terminal side, the signaling were done using polarity reversal and interrupting local loop (Pulse dialing).
From terminal side, after the receipt of central office command "collect token", terminal had to invert polarity for 50ms, failing in doing so, was interpreted as "no more tokens" and than call was ended by central office.

Our goal is therefore invert polarity when we need to say to the payphone to collect the token.
My first thought was to use polarity reversal feature, if fits, due to its widespread we can use almost any ATA on the market to have it. Not properly suited for this task, though.
Lets see.
From wikipedia: "Modern loop start trunks also have methods of answer supervision and disconnect supervision to alert a foreign exchange office (FXO) interface that the remote party has answered or hung up. Answer supervision usually takes the form of the central office reversing the polarity of the line for the duration of the call when it has been answered. This condition is called Reverse Battery or battery reversal. Disconnect supervision can take the form of the polarity reversing back. [...]"
It is quite different from what we need; the specification states: momentarily polarity reversal each time payphone needs to collect tokens, using this feature we have a unique polarity reversal from connection to the end of the call.
Projecting this feature on our device, the Italian U+I, the result is an odd behaviour that may be sufficient for someone, but which is definitely not what we want. We may observe, when call connects, the phone collecting the token and also switch its status to "out of order". Call does not drop, it continues until you hang up, and finally when you hang up, due to polarity reversion, the device tries again to collect a token while revert its status in "on line".
To have the control of the line the way we want we can not use any standard feature, we have to control the line directly.
Asterisk controls DAHDI devices directly through chan_dahdi channel driver. It means that to implement the standard feature battery reversal, the way you have on standard connection it have to "manually" invert the polarity on the line.

Reviewing code I could write a new dialplan application Polarity().
Using this new dialplan application is now possible to collect the first token, the one usually collected when the called party answers the line.
Here a dialplan to do so.

[payphone]
exten => _X.,            1,              Set(GLOBAL(cchan)=${CHANNEL})
exten => _X.,            n,              Dial(dahdi/1/${EXTEN},30,G(payphone,ANSWERED,1));

exten => ANSWERED,       1,              Goto(ANSWERED1,1)
exten => ANSWERED,       n,              Goto(ANSWERED2,1)
exten => ANSWERED1,      1,              polarity2(${GLOBAL(cchan)}, 500)
exten => ANSWERED1,      n,              Answer()
exten => ANSWERED2,      1,              wait(1)
exten => ANSWERED2,      2,              Bridge(${GLOBAL(cchan)})


Though using this application is now possible to revert the polarity the way we need when call connects, because Asterisk structure, the dialplan application can not be used during a connected call, the incall token collection feature is therefore still missing.
In a not so distant future I'd like to add a flag to the Dial dialplan application to revert polarity at prefixed time intervals starting when called party answers the call.

Friday, May 16, 2014

I2C driver for Sharp LM167511 lcd display

Recently I got into my hand this old digital phone.


The phone is part of a proprietary system of the early 90s, not so much useful today, but the display seems to be still useful, so I took apart it from the rest, and I begun to test its behaviour.
Display is branded Sharp model LM167511 and it is controled by the OKI MSM6262 chip.
The other 2 components present on the PCB are column drivers T6A39, not particulary interesting to control it.There's not a lot of documentation about this display provided by Sharp nor anyone else, and googling for its name you can only find an old post of a spanish guy asking if someone knows how to use it.
Using a multimeter and the datasheet of the OKI chip I mapped the chip pin on the control headers.


The most hard part has been understand how to use V5.
I thought to use it, in the same way I used to use V0 on the hd44780, the OKI chip expects a negative power on that pin! I got help on that.
But after that it was a piece of cake.
To control it I used an Arduino board and the following circuit:

The display has 7 lines of 16 characters each.
It also has a quite weird memory mapping. The followings are the first character address for each row:
0x08,0x48,0x88,0xc8,0x18,0x98
and this some code I wrote to drive this display.
LM167511.cpp
LM167511.h
sharp_expi2c.ino
that's all.