[Freeswitch-svn] [commit] r10776 - freeswitch/trunk/scripts/s25vmail

FreeSWITCH SVN brian at freeswitch.org
Mon Dec 15 10:16:35 PST 2008


Author: brian
Date: Mon Dec 15 13:16:34 2008
New Revision: 10776

Log:
FSSCRIPTS-8 Thanks John

Added:
   freeswitch/trunk/scripts/s25vmail/
   freeswitch/trunk/scripts/s25vmail/README
   freeswitch/trunk/scripts/s25vmail/s25vmail.js
   freeswitch/trunk/scripts/s25vmail/s25vmail_mwi.c

Added: freeswitch/trunk/scripts/s25vmail/README
==============================================================================
--- (empty file)
+++ freeswitch/trunk/scripts/s25vmail/README	Mon Dec 15 13:16:34 2008
@@ -0,0 +1,42 @@
+This directory contains software used for interfacing the
+FreeSWITCH voicemail application with the AT&T (aka Lucent
+aka Avaya) System 25 PBX.  It's possible that System 75
+and Definity PBXs may also work.
+
+s25vmail.js goes into the FreeSWITCH scripts directory.
+s25vmail_mwi.c should be compiled and the resulting binary
+put into the FreeSWITCH bin directory.  Modify the FreeSWITCH
+rc.d script to also start / stop s25vmail_mwi.
+
+Configuration fragments look something like:
+
+  conf/openzap.conf:
+
+    [span zt]
+    ; A204DX
+    name => OpenZAP
+    dtmf_hangup = ##99
+
+    number => 551
+    fxo-channel => 49
+
+    number => 552
+    fxo-channel => 50
+
+    number => 553
+    fxo-channel => 51
+
+    number => 554
+    fxo-channel => 52
+
+  conf/dialplan/default.xml
+
+    <extension name="system25_vmail">
+      <condition field="destination_number" expression="^(55[1-4])$">
+        <action application="javascript" data="s25vmail.js"/>
+      </condition>
+    </extension>
+
+Tested using FreeSWITCH SVN 10428 running on FreeBSD 6.3
+with a Sangoma A200DX Analog Series w/ Echo Cancellation
+ports card containing 2 FXO modules.

Added: freeswitch/trunk/scripts/s25vmail/s25vmail.js
==============================================================================
--- (empty file)
+++ freeswitch/trunk/scripts/s25vmail/s25vmail.js	Mon Dec 15 13:16:34 2008
@@ -0,0 +1,193 @@
+/*
+ *  File:    s25vmail.js
+ *  Purpose: Invoke voicemail based on AT&T System 25 PBX voicemail mode codes
+ *  Machine:                      OS:
+ *  Author:  John Wehle           Date: June 24, 2008
+ *
+ *  Copyright (c)  2008  Feith Systems and Software, Inc.
+ *                      All Rights Reserved
+ *
+ *  The message waiting indicator is handled by a separate program.
+ */
+
+
+var id_digits_required = 3;
+
+var digitTimeOut = 3000;
+var interDigitTimeOut = 1000;
+var absoluteTimeOut = 10000;
+
+
+var dtmf_digits = "";
+ 
+function on_dtmf (session, type, obj, arg)
+  {
+
+  if (type == "dtmf") {
+    dtmf_digits += obj.digit;
+    }
+
+  return true;
+  }
+
+
+function prompt_for_id ()
+  {
+  var id;
+  var index;
+  var repeat;
+  
+  dtmf_digits = "";
+  id = "";
+  repeat = 0;
+
+  while (session.ready () && repeat < 3) {
+    session.flushDigits ();
+  
+    /* play phrase - if digit keyed while playing callback will catch them*/
+    session.sayPhrase ("voicemail_enter_id", "#", "", on_dtmf, "");
+
+    if (! session.ready ())
+      return "";
+
+    id = dtmf_digits;
+
+    if (id.indexOf ('#') == -1) {
+      dtmf_digits = session.getDigits (5, '#', digitTimeOut,
+                                       interDigitTimeOut, absoluteTimeOut);
+      id += dtmf_digits;
+      id += '#';
+      }
+
+    /* a valid id must meet the minimum length requirements */
+    if ((index = id.indexOf ('#')) >= id_digits_required) {
+      id = id.substring (0,index);
+      break;
+      }
+
+    dtmf_digits = "";
+    id = "";
+    repeat++;
+    }
+
+  return id;
+  }
+
+
+var start = "";
+var mode = "";
+var from = "";
+var to = "";
+
+var domain = session.getVariable ("domain");
+
+session.answer ();
+
+start = session.getDigits (1, '', digitTimeOut,
+                           interDigitTimeOut, absoluteTimeOut);
+
+if (start != "#") {
+  console_log ("err", "Invalid VMAIL start code from PBX\n");
+  exit();
+  }
+
+mode = session.getDigits (5, '#', digitTimeOut,
+                          interDigitTimeOut, absoluteTimeOut);
+
+from = session.getDigits (5, '#', digitTimeOut,
+                          interDigitTimeOut, absoluteTimeOut);
+
+to = session.getDigits (5, '#', digitTimeOut,
+                        interDigitTimeOut, absoluteTimeOut);
+
+session.execute("sleep", "1000");
+
+// Verify that the proper parameters are present
+switch (mode) {
+
+  // Direct Inside Access
+  case "00":
+    if (isNaN (parseInt (from, 10))) {
+      console_log ("err", "Invalid VMAIL calling PDC from PBX\n");
+      break;
+      }
+
+    session.setVariable ("voicemail_authorized", "false");
+    session.execute ("voicemail", "check default " + domain + " " + from);
+    break;
+
+  // Direct Dial Access
+  case "01":
+    from = prompt_for_id ();
+
+    if (! session.ready ()) {
+      session.hangup();
+      exit();
+      }
+
+    if (isNaN (parseInt (from, 10))) {
+      console_log ("err", "Invalid VMAIL mailbox from caller\n");
+      break;
+      }
+
+    session.setVariable ("voicemail_authorized", "false");
+    session.execute ("voicemail", "check default " + domain + " " + from);
+    break;
+
+  // Coverage - caller is inside
+  case "02":
+    if (isNaN (parseInt (from, 10)) || isNaN (parseInt (to, 10))) {
+      console_log ("err", "Invalid VMAIL calling or called PDC from PBX\n");
+      break;
+      }
+
+    session.setVariable ("effective_caller_id_name", "inside caller");
+    session.setVariable ("effective_caller_id_number", from);
+
+    session.execute ("voicemail", "default " + domain + " " + to);
+    break;
+
+  // Coverage - caller is dial
+  case "03":
+    if (isNaN (parseInt (to, 10))) {
+      console_log ("err", "Invalid VMAIL called PDC from PBX\n");
+      break;
+      }
+
+    session.setVariable ("effective_caller_id_name", "outside caller");
+    session.setVariable ("effective_caller_id_number", "Unknown");
+
+    session.execute ("voicemail", "default " + domain + " " + to);
+    break;
+
+  // Coverage - not yet defined
+  case "04":
+    break;
+
+  // Leave Word Calling
+  case "05":
+    if (isNaN (parseInt (from, 10)) || isNaN (parseInt (to, 10))) {
+      console_log ("err", "Invalid VMAIL calling or called PDC from PBX\n");
+      break;
+      }
+    break;
+
+  // Refresh MW lamps
+  case "06":
+    break;
+
+  // Voice Port failed to answer
+  case "08":
+    if (isNaN (parseInt (to, 10))) {
+      console_log ("err", "Invalid VMAIL PDC from PBX\n");
+      break;
+      }
+    break;
+
+  // Unknown
+  default:
+    console_log ("err", "Invalid VMAIL mode code from PBX\n");
+    break;
+  }
+
+exit();

Added: freeswitch/trunk/scripts/s25vmail/s25vmail_mwi.c
==============================================================================
--- (empty file)
+++ freeswitch/trunk/scripts/s25vmail/s25vmail_mwi.c	Mon Dec 15 13:16:34 2008
@@ -0,0 +1,953 @@
+/*
+ *  File:    s25vmail_mwi.c
+ *  Purpose: Send AT&T System 25 PBX MWI DTMF based on MWI events
+ *  Machine:                      OS:
+ *  Author:  John Wehle           Date: July 24, 2008
+ *
+ *  Copyright (c)  2008  Feith Systems and Software, Inc.
+ *                      All Rights Reserved
+ *
+ *  Tested using a Zyxel U90e configured using:
+ *
+ *    at OK at&f OK at&d3&y2q2 OK ats0=0s2=255s15.7=0s18=4s35.1=0 OK
+ *    ats38.3=1s42.3=1s42.6=1 OK atl0 OK at&w OK at&v
+ *
+ *  though just about any modem should work.  Preferred settings are
+ *
+ *    DTR OFF causes hangup and reset from profile 0
+ *    RTS / CTS flow control
+ *    allow abort during modem handshake
+ *    auto answer off
+ *    ring message off
+ */
+
+
+#include <ctype.h>
+#include <errno.h>
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <fcntl.h>
+#include <memory.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <signal.h>
+#include <termios.h>
+
+#include <netdb.h>
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <sys/socket.h>
+#include <sys/param.h>
+#include <unistd.h>
+
+
+#define LOGFILE                    "/var/log/s25vmail_mwi.log"
+
+
+static const char *MyName = "s25vmail_mwi";
+
+static int daimon = 0;
+static int error_msg_throttle = 0;
+static volatile int shutdown_server = 0;
+
+
+static void
+debugmsg (const char *fmt, ...)
+  {
+  char message[256];
+  va_list args;
+
+  if (daimon)
+    return;
+
+  va_start (args, fmt);
+  vsprintf (message, fmt, args);
+  va_end (args);
+
+  fprintf (stderr, "%s: %s", MyName, message);
+  if ( !strchr (message, '\n'))
+    fprintf (stderr, "\n");
+  fflush (stderr);
+  }
+
+
+static void
+errmsg (const char *fmt, ...)
+  {
+  char time_stamp[256];
+  struct tm *tmp;
+  time_t now;
+  va_list args;
+
+  if (! daimon) {
+    fprintf (stderr, "%s: ", MyName);
+
+    va_start (args, fmt);
+    vfprintf (stderr, fmt, args);
+    va_end (args);
+
+    if (! strchr (fmt, '\n'))
+      fputc ('\n', stderr);
+
+    fflush (stderr);
+    return;
+    }
+
+  if (error_msg_throttle)
+    return;
+
+  time (&now);
+
+  if ( !(tmp = localtime (&now)) ) {
+    fprintf (stderr, "%s: errmsg -- localtime failed.\n", MyName);
+    perror (MyName);
+    fflush (stderr);
+    return;
+    }
+
+  strftime (time_stamp, sizeof (time_stamp), "%b %d %H:%M:%S", tmp);
+  fprintf (stderr, "%s %s[%d]: ", time_stamp, MyName, (int)getpid ());
+
+  va_start (args, fmt);
+  vfprintf (stderr, fmt, args);
+  va_end (args);
+
+  if (! strchr (fmt, '\n'))
+    fputc ('\n', stderr);
+
+  fflush (stderr);
+  }
+
+
+static void
+catch_signal ()
+  {
+
+  shutdown_server = 1;
+  }
+
+
+static void
+daemonize()
+  {
+
+#ifdef SIGTSTP
+  (void)signal(SIGTSTP, SIG_IGN);
+#endif
+#ifdef SIGTTIN
+  (void)signal(SIGTTIN, SIG_IGN);
+#endif
+#ifdef SIGTTOU
+  (void)signal(SIGTTOU, SIG_IGN);
+#endif
+
+  switch (fork ()) {
+    case 0:
+      break;
+
+    case -1:
+      fprintf (stderr, "%s: daemonize -- fork failed.", MyName);
+      perror (MyName);
+      exit (1);
+    /* NOTREACHED */
+      break;
+
+    default:
+      exit (0);
+    /* NOTREACHED */
+      break;
+    }
+
+  setsid();
+
+  close (0);
+  close (1);
+  close (2);
+
+  (void)open ("/dev/null", O_RDWR);
+  (void)open ("/dev/null", O_RDWR);
+  (void)open (LOGFILE, O_WRONLY | O_APPEND | O_CREAT, 0644);
+
+  daimon = 1;
+  }
+
+
+static void
+install_signal_handlers ()
+  {
+  struct sigaction act;
+
+  memset (&act, '\0', sizeof (act));
+
+  act.sa_handler = catch_signal;
+  sigemptyset (&act.sa_mask);
+  act.sa_flags = 0;
+
+  if (signal (SIGHUP, SIG_IGN) != SIG_IGN)
+    sigaction (SIGHUP, &act, NULL);
+  if (signal (SIGINT, SIG_IGN) != SIG_IGN)
+    sigaction (SIGINT, &act, NULL);
+  (void)sigaction (SIGTERM, &act, NULL);
+  }
+
+
+static int
+connect_to_service (const char *hostname, const char *port)
+  {
+  int sock;
+  struct hostent *hp;
+  struct in_addr address;
+  struct servent *servp;
+  struct sockaddr_in sin;
+  
+  if ((sock = socket (AF_INET, SOCK_STREAM, IPPROTO_TCP)) == -1) {
+    char *errstr = strerror (errno);
+
+    errmsg ("socket failed\n");
+    errmsg (errstr);
+    return -1;
+    }
+
+  memset (&sin, 0, sizeof (sin));
+
+  if (isalpha (hostname[0])) {
+    if ( !(hp = gethostbyname (hostname))) {
+      char *errstr = strerror (errno);
+
+      errmsg ("gethostbyname failed\n");
+      errmsg (errstr);
+      close (sock);
+      return -1;
+      }
+    if (hp->h_addrtype != AF_INET) {
+      errmsg ("gethostbyname returned unsupported family\n");
+      close (sock);
+      return -1;
+      }
+    memcpy (&sin.sin_addr, hp->h_addr, sizeof(sin.sin_addr));
+    }
+  else {
+    address.s_addr = inet_addr (hostname);
+
+    if ((long)address.s_addr == -1) {
+      char *errstr = strerror (errno);
+
+      errmsg ("inet_addr failed\n");
+      errmsg (errstr);
+      close (sock);
+      return -1;
+      }
+    sin.sin_addr.s_addr = address.s_addr;
+    }
+
+  if (isalpha (*port)) {
+    if ( !(servp = getservbyname(port, "tcp"))) {
+      char *errstr = strerror (errno);
+
+      errmsg ("getservbyname failed\n");
+      errmsg (errstr);
+      close (sock);
+      return -1;
+      }
+    sin.sin_port = servp->s_port;
+    }
+  else
+    sin.sin_port = htons ((unsigned short)atoi (port));
+
+  sin.sin_family = AF_INET;
+
+  if (connect (sock, (struct sockaddr *)&sin, sizeof(sin)) == -1) {
+    char *errstr = strerror (errno);
+
+    errmsg ("connect failed\n");
+    errmsg (errstr);
+    close (sock);
+    return -1;
+    }
+
+  debugmsg ("Connected to service\n");
+
+  return sock;
+  }
+
+
+static ssize_t
+read_line (int fd, char *buf, size_t buf_len)
+  {
+  size_t l;
+  ssize_t nbytes_read;
+
+  l = 0;
+
+  for ( ; ; ) {
+    nbytes_read = read (fd, &buf[l], 1);
+
+    if (nbytes_read < 0) {
+      char *errstr = strerror (errno);
+
+      errmsg ("read failed in middle of line\n");
+      errmsg (errstr);
+      return -1;
+      }
+
+    if (nbytes_read == 0) {
+      if (l)
+        errmsg ("EOF in middle of line\n");
+      return l ? -1 : 0;
+      }
+
+    if (buf[l] == '\n') {
+      while (l && buf[l - 1] == '\r')
+        l--;
+      buf[l++] = '\0';
+      break;
+      }
+
+    l++;
+
+    if (l == buf_len) {
+      errmsg ("line too long\n");
+      return -1;
+      }
+    }
+
+  return l;
+  }
+
+
+static int
+read_trailing_newline(int fd)
+  {
+  char c;
+  ssize_t nbytes_read;
+
+  nbytes_read = read (fd, &c, 1);
+
+  if (nbytes_read < 0) {
+    char *errstr = strerror (errno);
+
+    errmsg ("read failed in trailing newline\n");
+    errmsg (errstr);
+    return -1;
+    }
+
+  if (nbytes_read == 0) {
+    errmsg ("EOF in trailing newline\n");
+    return -1;
+    }
+
+  if (c != '\n') {
+    errmsg ("missing trailing newline\n");
+    return -1;
+    }
+
+  return 0;
+  }
+
+
+static char *
+retrieve_message (int fd)
+  {
+  char cl_buf[64];
+  char ct_buf[64];
+  char *h;
+  char *m;
+  ssize_t cl;
+  ssize_t nbytes_read;
+  size_t l;
+  size_t nbytes_to_read;
+
+  if (shutdown_server)
+    return NULL;
+
+  /*
+   * Read / parse Content-Length and Content-Type.
+   */
+
+  nbytes_read = read_line (fd, cl_buf, sizeof (cl_buf));
+
+  if (nbytes_read < 0) {
+    errmsg ("read_line failed\n");
+    return NULL;
+    }
+
+  if (nbytes_read == 0) {
+
+    /*
+     * EOF
+     */
+
+    return NULL;
+    }
+
+  nbytes_read = read_line (fd, ct_buf, sizeof (ct_buf));
+
+  if (nbytes_read < 0) {
+    errmsg ("read_line failed\n");
+    return NULL;
+    }
+
+  if (nbytes_read == 0) {
+    errmsg ("EOF in middle of headers\n");
+    return NULL;
+    }
+
+  h = "Content-Length: ";
+  l = strlen (h);
+
+  if (strncmp (cl_buf, h, l) != 0) {
+
+    /*
+     * If the message header doesn't being with Content-Length,
+     * then it needs to be a Content-Type we understand.
+     */
+
+    h = "Content-Type: ";
+    l = strlen (h);
+
+    if (strncmp (cl_buf, h, l) != 0) {
+      errmsg ("missing Content-Type\n");
+      return NULL;
+      }
+
+    if (strcmp (&cl_buf[l], "auth/request") != 0
+        && strcmp (&cl_buf[l], "command/reply") != 0) {
+      errmsg ("Unsupported Content-Type\n");
+      return NULL;
+      }
+
+    if (ct_buf[0])
+      if (read_trailing_newline (fd) < 0) {
+        return NULL;
+        }
+
+    m = malloc (strlen (cl_buf) + 1 + strlen (ct_buf) + 1 + 1);
+
+    if (! m) {
+      char *errstr = strerror (errno);
+
+      errmsg ("malloc failed\n");
+      errmsg (errstr);
+      return NULL;
+      }
+
+    sprintf (m, "%s\n%s\n", cl_buf, ct_buf);
+
+    return m;
+    }
+
+  cl = atoi (&cl_buf[l]);
+
+  if (cl <= 0) {
+    errmsg ("Content-Length must be greater than zero\n");
+    return NULL;
+    }
+
+  h = "Content-Type: ";
+  l = strlen (h);
+
+  if (strncmp (ct_buf, h, l) != 0) {
+    errmsg ("missing Content-Type\n");
+    return NULL;
+    }
+
+  if (strcmp (&ct_buf[l], "text/event-plain") != 0) {
+    errmsg ("Unsupported Content-Type\n");
+    return NULL;
+    }
+
+  if (read_trailing_newline (fd) < 0) {
+    return NULL;
+    }
+
+  /*
+   * Read the event.
+   */
+
+  m = malloc (cl);
+
+  if (! m) {
+    char *errstr = strerror (errno);
+
+    errmsg ("malloc failed\n");
+    errmsg (errstr);
+    return NULL;
+    }
+
+  for (nbytes_to_read = cl; nbytes_to_read; nbytes_to_read -= nbytes_read) {
+    nbytes_read = read (fd, m + (cl - nbytes_to_read), nbytes_to_read);
+
+    if (nbytes_read < 0) {
+      char *errstr = strerror (errno);
+
+      errmsg ("read failed in middle of message\n");
+      errmsg (errstr);
+      free (m);
+      return NULL;
+      }
+
+    if (nbytes_read == 0) {
+      errmsg ("EOF in middle of message\n");
+      free (m);
+      return NULL;
+      }
+    }
+
+  if (m[cl - 2] != '\n' || m[cl - 1] != '\n') {
+    errmsg ("Message is missing trailing newlines\n");
+    free (m);
+    return NULL;
+    }
+
+  return m;
+  }
+
+
+static int
+send_password (int fd, const char *passwd)
+  {
+  char *h;
+  char *last;
+  char *m;
+  char *p;
+  int l;
+  size_t ml;
+
+  m = retrieve_message (fd);
+  if (! m)
+    return -1;
+
+  p = strtok_r (m, "\n", &last);
+
+  h = "Content-Type: auth/request";
+
+  if (strcmp (p, h) != 0) {
+    errmsg ("Content-Type wasn't auth/request\n");
+    free (m);
+    return -1;
+    }
+
+  free (m);
+
+  l = snprintf (NULL, 0, "auth %s\n\n", passwd);
+  if (l <= 0) {
+    errmsg ("snprintf failed\n");
+    return -1;
+    }
+  l++;
+
+  m = malloc (l);
+  if (! m) {
+    char *errstr = strerror (errno);
+
+    errmsg ("malloc failed\n");
+    errmsg (errstr);
+    return -1;
+    }
+
+  ml = snprintf (m, l, "auth %s\n\n", passwd);
+  if ((ml + 1) != l) {
+    errmsg ("snprintf failed\n");
+    free (m);
+    return -1;
+    }
+
+  if (write (fd, m, ml) != ml) {
+    char *errstr = strerror (errno);
+
+    errmsg ("write failed\n");
+    errmsg (errstr);
+    free (m);
+    return -1;
+    }
+
+  m = retrieve_message (fd);
+  if (! m )
+    return -1;
+
+  p = strtok_r (m, "\n", &last);
+
+  h = "Content-Type: command/reply";
+
+  if (! p || strcmp (p, h) != 0) {
+    errmsg ("Content-Type wasn't command/reply\n");
+    free (m);
+    return -1;
+    }
+
+  p = strtok_r (NULL, "\n", &last);
+
+  h = "Reply-Text: +OK accepted";
+
+  if (! p || strcmp (p, h) != 0) {
+    errmsg ("auth wasn't accepted\n");
+    free (m);
+    return -1;
+    }
+
+  free (m);
+
+  debugmsg ("Logged into service\n");
+
+  return 0;
+  }
+
+
+static int
+enable_mwi_event (int fd)
+  {
+  char *h;
+  char *last;
+  char *m;
+  char *p;
+  size_t ml;
+
+  m = "event plain MESSAGE_WAITING\n\n";
+  ml = strlen (m);
+
+  if (write (fd, m, ml) != ml) {
+    char *errstr = strerror (errno);
+
+    errmsg ("write failed\n");
+    errmsg (errstr);
+    return -1;
+    }
+
+  m = retrieve_message (fd);
+  if (! m )
+    return -1;
+
+  p = strtok_r (m, "\n", &last);
+
+  h = "Content-Type: command/reply";
+
+  if (! p || strcmp (p, h) != 0) {
+    errmsg ("Content-Type wasn't command/reply\n");
+    free (m);
+    return -1;
+    }
+
+  p = strtok_r (NULL, "\n", &last);
+
+  h = "Reply-Text: +OK event listener enabled plain";
+
+  if (! p || strcmp (p, h) != 0) {
+    errmsg ("event wasn't enabled\n");
+    free (m);
+    return -1;
+    }
+
+  free (m);
+
+  debugmsg ("Enabled message waiting event\n");
+
+  return 0;
+  }
+
+
+static int
+process_mwi_event (char *m, const char *device)
+  {
+  char cbuf[64];
+  char rbuf[64];
+  char *h;
+  char *last;
+  char *ma;
+  char *mw;
+  char *p;
+  int fd;
+  int mwi_off;
+  int mwi_on;
+  int r;
+  int w;
+  size_t l;
+  ssize_t ml;
+  ssize_t nbytes_read;
+  struct termios tio;
+
+  debugmsg ("Processing MWI event\n");
+
+  ma = NULL;
+  mw = NULL;
+
+  p = m;
+
+  while ( (p = strtok_r (p, "\n", &last)) ) {
+    h = "MWI-Messages-Waiting: ";
+    l = strlen (h);
+
+    if (strncmp (p, h, l) == 0)
+      mw = p + l;
+
+    h = "MWI-Message-Account: ";
+    l = strlen (h);
+
+    if (strncmp (p, h, l) == 0)
+      ma = p + l;
+
+    p = NULL;
+    }
+
+  if (! (ma && mw) ) {
+    errmsg ("message account or message waiting missing\n");
+    return -1;
+    }
+
+  p = strchr (ma, '\n');
+  if (p)
+    *p = '\n';
+
+  p = strchr (mw, '\n');
+  if (p)
+    *p = '\n';
+
+  /*
+   * The account is considered to be a System 25 extension if
+   * it's of the form:
+   *
+   *   numeric_string at host
+   */
+
+  p = strchr (ma, '%');
+  if (! p)
+    p = strchr (ma, '@');
+
+  if (! p || (strncmp (p, "%40", 3) != 0 && strncmp (p, "@", 1) != 0)) {
+    debugmsg ("  %s is not a System 25 extension\n", ma);
+    return 0;
+    }
+
+  *p = '\0';
+
+  for (p = ma; *p; p++)
+    if (! isdigit (*p)) {
+      debugmsg ("  %s is not a System 25 extension\n", ma);
+      return 0;
+      }
+
+  mwi_off = strcasecmp (mw, "no") == 0;
+  mwi_on = strcasecmp (mw, "yes") == 0;
+
+  if (mwi_off == mwi_on) {
+    errmsg ("Unsupported Messages-Waiting\n");
+    return 0;
+    }
+
+  for (r = 0; r < 3; r++) {
+    if ((fd = open (device, O_RDWR)) < 0) {
+      char *errstr = strerror (errno);
+
+      errmsg ("open failed for device node <%s>.\n", device);
+      errmsg (errstr);
+      return -1;
+      }
+
+    cfmakeraw (&tio);
+
+    tio.c_cflag = CS8 | CREAD | HUPCL | CCTS_OFLOW | CRTS_IFLOW;
+
+    tio.c_cc[VMIN] = 0;
+    tio.c_cc[VTIME] = 50;
+
+    cfsetispeed (&tio, B9600);
+    cfsetospeed (&tio, B9600);
+
+    if (tcsetattr (fd, TCSAFLUSH, &tio) < 0) {
+      char *errstr = strerror (errno);
+
+      errmsg ("tcsetattr failed\n");
+      errmsg (errstr);
+      close (fd);
+      return -1;
+      }
+
+    m = "AT";
+    ml = strlen (m);
+
+    if (write (fd, m, ml) != ml
+        || write (fd, "\r\n", 2) != 2) {
+      char *errstr = strerror (errno);
+
+      errmsg ("write failed\n");
+      errmsg (errstr);
+      close (fd);
+      return -1;
+      }
+
+    for (w = 0; w < 2; w++) {
+      nbytes_read = read_line (fd, rbuf, sizeof (rbuf));
+      if (nbytes_read > 0 && (rbuf[0] == '\0' || strcmp (rbuf, m) == 0))
+        continue;
+      break;
+      }
+
+    if (nbytes_read < 0) {
+      errmsg ("read_line failed\n");
+      close (fd);
+      return -1;
+      }
+
+    if (nbytes_read == 0
+        || strcmp (rbuf, "OK") != 0) {
+      errmsg ("modem failed to wake up\n");
+      close (fd);
+      continue;
+      }
+
+    m = cbuf;
+    ml  = snprintf (cbuf, sizeof (cbuf),
+                    "ATDT%s%s", (mwi_on ? "#90" : "#91"),  ma);
+    if (ml <= 0 || ml >= sizeof (cbuf)) {
+      errmsg ("snprintf failed.\n");
+      close (fd);
+      return -1;
+      }
+
+    if (write (fd, m, ml) != ml
+        || write (fd, "\r\n", 2) != 2) {
+      char *errstr = strerror (errno);
+
+      errmsg ("write failed\n");
+      errmsg (errstr);
+      close (fd);
+      return -1;
+      }
+
+    sleep (5);
+
+    if (write (fd, "\r\n", 2) != 2) {
+      char *errstr = strerror (errno);
+
+      errmsg ("write failed\n");
+      errmsg (errstr);
+      close (fd);
+      return -1;
+      }
+
+    for (w = 0; w < 2; w++) {
+      nbytes_read = read_line (fd, rbuf, sizeof (rbuf));
+      if (nbytes_read > 0 && (rbuf[0] == '\0' || strcmp (rbuf, m) == 0))
+        continue;
+      break;
+      }
+
+    if (nbytes_read < 0) {
+      errmsg ("read_line failed\n");
+      close (fd);
+      return -1;
+      }
+
+    if (nbytes_read > 0 && strcmp (rbuf, "NO DIALTONE") == 0) {
+      errmsg ("modem failed to detect dialtone\n");
+      close (fd);
+      return -1;
+      }
+
+    if (nbytes_read == 0
+        || strcmp (rbuf, "NO CARRIER") != 0) {
+      errmsg ("modem failed to update MWI\n");
+      close (fd);
+      continue;
+      }
+
+    close (fd);
+
+    debugmsg ("  message waiting indicator updated for %s\n", ma);
+    return 0;
+    }
+
+  errmsg (" failed to update message waiting indicator for %s\n", ma);
+
+  return -1;
+  }
+
+
+int
+main (int argc, char **argv)
+  {
+  const char *device = "/dev/cuad0";
+  const char *machine = "localhost";
+  const char *port = "8021";
+  const char *passwd = "ClueCon";
+  char *m;
+  int c;
+  int debug;
+  int fd;
+  struct stat statbuf;
+
+  debug = 0;
+
+  while ((c = getopt (argc, argv, "dm:p:w:")) != -1)
+    switch (c) {
+      case 'd':
+        debug = 1;
+        break;
+
+      case 'm':
+        machine = optarg;
+        break;
+
+      case 'p':
+        port = optarg;
+        break;
+
+      case 'w':
+        passwd = optarg;
+        break;
+
+      case 'l':
+        device = optarg;
+        break;
+
+      default:
+        fprintf (stderr,
+          "Usage: %s [-d] [-m machine] [-p port] [-w passwd] [-l device]\n",
+                 MyName);
+        exit(1);
+      /* NOTREACHED */
+        break;
+      }
+
+  if (stat (device, &statbuf) < 0 || ! S_ISCHR (statbuf.st_mode)) {
+    fprintf (stderr, "%s: stat failed for path <%s>\n", MyName, device);
+    fprintf (stderr, "%s: or the path isn't a character special file.\n",
+             MyName);
+    perror (MyName);
+    exit (1);
+    }
+
+  install_signal_handlers ();
+
+  if (! debug)
+    daemonize ();
+
+  while (! shutdown_server) {
+    sleep (5);
+
+    fd = connect_to_service (machine, port);
+    if (fd < 0) {
+      error_msg_throttle = 1;
+      continue;
+      }
+
+    if (send_password (fd, passwd) < 0
+        || enable_mwi_event (fd) < 0) {
+      error_msg_throttle = 1;
+      close (fd);
+      continue;
+      }
+
+    error_msg_throttle = 0;
+
+    while (m = retrieve_message (fd)) {
+      process_mwi_event (m, device);
+      free (m);
+      }
+
+    close (fd);
+    }
+
+  exit (0);
+  }



More information about the Freeswitch-svn mailing list