Restore some missing functionality to sig_analog.
authorJeff Peeler <jpeeler@digium.com>
Tue, 14 Jul 2009 20:01:10 +0000 (20:01 +0000)
committerJeff Peeler <jpeeler@digium.com>
Tue, 14 Jul 2009 20:01:10 +0000 (20:01 +0000)
The main purpose of this commit is to restore missing functionality present in
the ss_thread before all the sig related work was done. Two of the biggest
missing things were distinctive ring detection and cid handling for V23.
fxsoffhookstate and associated mwi variables have been moved inside sig_analog
as they were not being set properly as well.

git-svn-id: https://origsvn.digium.com/svn/asterisk/trunk@206566 65c4cc65-6c06-0410-ace0-fbb531ad65f3

channels/chan_dahdi.c
channels/sig_analog.c
channels/sig_analog.h

index 7e545d0..c1e8628 100644 (file)
@@ -63,6 +63,11 @@ ASTERISK_FILE_VERSION(__FILE__, "$Revision$")
 #include <dahdi/user.h>
 #include <dahdi/tonezone.h>
 #include "sig_analog.h"
+/* Analog signaling is currently still present in chan_dahdi for use with
+ * radio. Sig_analog does not currently handle any radio operations. If
+ * radio only uses analog signaling, then the radio handling logic could
+ * be placed in sig_analog and the duplicated code could be removed.
+ */
 
 #ifdef HAVE_PRI
 #include "sig_pri.h"
@@ -364,6 +369,37 @@ static const char config[] = "chan_dahdi.conf";
 #define CALLPROGRESS_FAX_INCOMING      4
 #define CALLPROGRESS_FAX               (CALLPROGRESS_FAX_INCOMING | CALLPROGRESS_FAX_OUTGOING)
 
+#define NUM_CADENCE_MAX 25
+static int num_cadence = 4;
+static int user_has_defined_cadences = 0;
+
+static struct dahdi_ring_cadence cadences[NUM_CADENCE_MAX] = {
+       { { 125, 125, 2000, 4000 } },                   /*!< Quick chirp followed by normal ring */
+       { { 250, 250, 500, 1000, 250, 250, 500, 4000 } }, /*!< British style ring */
+       { { 125, 125, 125, 125, 125, 4000 } },  /*!< Three short bursts */
+       { { 1000, 500, 2500, 5000 } },  /*!< Long ring */
+};
+
+/*! \brief cidrings says in which pause to transmit the cid information, where the first pause
+ * is 1, the second pause is 2 and so on.
+ */
+
+static int cidrings[NUM_CADENCE_MAX] = {
+       2,                                                                              /*!< Right after first long ring */
+       4,                                                                              /*!< Right after long part */
+       3,                                                                              /*!< After third chirp */
+       2,                                                                              /*!< Second spell */
+};
+
+/* ETSI EN300 659-1 specifies the ring pulse between 200 and 300 mS */
+static struct dahdi_ring_cadence AS_RP_cadence = {{250, 10000}};
+
+#define ISTRUNK(p) ((p->sig == SIG_FXSLS) || (p->sig == SIG_FXSKS) || \
+                       (p->sig == SIG_FXSGS) || (p->sig == SIG_PRI))
+
+#define CANBUSYDETECT(p) (ISTRUNK(p) || (p->sig & (SIG_EM | SIG_EM_E1 | SIG_SF)) /* || (p->sig & __DAHDI_SIG_FXO) */)
+#define CANPROGRESSDETECT(p) (ISTRUNK(p) || (p->sig & (SIG_EM | SIG_EM_E1 | SIG_SF)) /* || (p->sig & __DAHDI_SIG_FXO) */)
+
 static char defaultcic[64] = "";
 static char defaultozz[64] = "";
 
@@ -1153,19 +1189,12 @@ static struct dahdi_pvt {
        struct ast_event_sub *mwi_event_sub;
        /*! \brief Delayed dialing for E911.  Overlap digits for ISDN. */
        char dialdest[256];
-       /*! \brief Time the interface went on-hook. */
-       int onhooktime;
-       /*! \brief TRUE if the FXS port is off-hook */
-       int fxsoffhookstate;
-       /*! \brief -1 = unknown, 0 = no messages, 1 = new messages available */
-       int msgstate;
 #ifdef HAVE_DAHDI_LINEREVERSE_VMWI
        struct dahdi_vmwi_info mwisend_setting;                         /*!< Which VMWI methods to use */
        unsigned int mwisend_fsk: 1;            /*! Variable for enabling FSK MWI handling in chan_dahdi */
        unsigned int mwisend_rpas:1;            /*! Variable for enabling Ring Pulse Alert before MWI FSK Spill */
 #endif
        int distinctivering;                            /*!< Which distinctivering to use */
-       int cidrings;                                   /*!< Which ring to deliver CID on */
        int dtmfrelax;                                  /*!< whether to run in relaxed DTMF mode */
        /*! \brief Holding place for event injected from outside normal operation. */
        int fake_event;
@@ -1177,7 +1206,7 @@ static struct dahdi_pvt {
        /*! \brief Start delay time if polarityonanswerdelay is nonzero. */
        struct timeval polaritydelaytv;
        /*!
-        * \brief Send caller ID after this many rings.
+        * \brief Send caller ID on FXS after this many rings. Set to 1 for US.
         * \note Set from the "sendcalleridafter" value read in from chan_dahdi.conf
         */
        int sendcalleridafter;
@@ -1557,6 +1586,7 @@ static int my_stop_cid_detect(void *pvt)
 static int my_get_callerid(void *pvt, char *namebuf, char *numbuf, enum analog_event *ev, size_t timeout)
 {
        struct dahdi_pvt *p = pvt;
+       struct analog_pvt *analog_p = p->sig_pvt;
        struct pollfd poller;
        char *name, *num;
        int index = SUB_REAL;
@@ -1578,9 +1608,9 @@ static int my_get_callerid(void *pvt, char *namebuf, char *numbuf, enum analog_e
        if (poller.revents & POLLIN) {
                /*** NOTES ***/
                /* Change API: remove cid_signalling from get_callerid, add a new start_cid_detect and stop_cid_detect function
-                * to enable slin mode and allocate cid detector.  get_callerid should be able to be called any number of times until
-                * either a timeout occurss or CID is detected (returns 0).  returning 1 should be event received, and -1 should be fail
-                * and die */
+                * to enable slin mode and allocate cid detector. get_callerid should be able to be called any number of times until
+                * either a timeout occurss or CID is detected (returns 0). returning 1 should be event received, and -1 should be
+                * a failure and die, and returning 2 means no event was received. */
                res = read(p->subs[index].dfd, buf, sizeof(buf));
                if (res < 0) {
                        if (errno != ELAST) {
@@ -1589,7 +1619,20 @@ static int my_get_callerid(void *pvt, char *namebuf, char *numbuf, enum analog_e
                                return -1;
                        }
                }
-               res = callerid_feed(p->cs, buf, res, AST_LAW(p));
+
+               if (analog_p->ringt) {
+                       analog_p->ringt--;
+               }
+               if (analog_p->ringt == 1) {
+                       return -1;
+               }
+
+               if (p->cid_signalling == CID_SIG_V23_JP) {
+                       res = callerid_feed_jp(p->cs, buf, res, AST_LAW(p));
+               } else {
+                       res = callerid_feed(p->cs, buf, res, AST_LAW(p));
+               }
+
                if (res < 0) {
                        ast_log(LOG_WARNING, "CallerID feed failed: %s\n", strerror(errno));
                        return -1;
@@ -1608,7 +1651,128 @@ static int my_get_callerid(void *pvt, char *namebuf, char *numbuf, enum analog_e
        }
 
        *ev = ANALOG_EVENT_NONE;
-       return 1;
+       return 2;
+}
+
+static const char *event2str(int event);
+static int restore_gains(struct dahdi_pvt *p);
+
+static int my_distinctive_ring(struct ast_channel *chan, void *pvt, int idx, int *ringdata)
+{
+       unsigned char buf[256];
+       int distMatches;
+       int curRingData[3];
+       int receivedRingT;
+       int counter1;
+       int counter;
+       int i;
+       int res;
+       int checkaftercid = 0;
+
+       struct dahdi_pvt *p = pvt;
+       struct analog_pvt *analog_p = p->sig_pvt;
+
+       if (ringdata == NULL) {
+               ringdata = curRingData;
+       } else {
+               checkaftercid = 1;
+       }
+
+       /* We must have a ring by now, so, if configured, lets try to listen for
+        * distinctive ringing */
+       if ((checkaftercid && distinctiveringaftercid) || !checkaftercid) {
+               /* Clear the current ring data array so we dont have old data in it. */
+               for (receivedRingT = 0; receivedRingT < ARRAY_LEN(ringdata); receivedRingT++)
+                       ringdata[receivedRingT] = 0;
+               receivedRingT = 0;
+               if (checkaftercid && distinctiveringaftercid)
+                       ast_verb(3, "Detecting post-CID distinctive ring\n");
+               /* Check to see if context is what it should be, if not set to be. */
+               else if (strcmp(p->context,p->defcontext) != 0) {
+                       ast_copy_string(p->context, p->defcontext, sizeof(p->context));
+                       ast_copy_string(chan->context,p->defcontext,sizeof(chan->context));
+               }
+
+               for (;;) {
+                       i = DAHDI_IOMUX_READ | DAHDI_IOMUX_SIGEVENT;
+                       if ((res = ioctl(p->subs[idx].dfd, DAHDI_IOMUX, &i))) {
+                               ast_log(LOG_WARNING, "I/O MUX failed: %s\n", strerror(errno));
+                               ast_hangup(chan);
+                               return 1;
+                       }
+                       if (i & DAHDI_IOMUX_SIGEVENT) {
+                               res = dahdi_get_event(p->subs[idx].dfd);
+                               ast_log(LOG_NOTICE, "Got event %d (%s)...\n", res, event2str(res));
+                               res = 0;
+                               /* Let us detect distinctive ring */
+
+                               ringdata[receivedRingT] = analog_p->ringt;
+
+                               if (analog_p->ringt < analog_p->ringt_base/2)
+                                       break;
+                               /* Increment the ringT counter so we can match it against
+                                  values in chan_dahdi.conf for distinctive ring */
+                               if (++receivedRingT == ARRAY_LEN(ringdata))
+                                       break;
+                       } else if (i & DAHDI_IOMUX_READ) {
+                               res = read(p->subs[idx].dfd, buf, sizeof(buf));
+                               if (res < 0) {
+                                       if (errno != ELAST) {
+                                               ast_log(LOG_WARNING, "read returned error: %s\n", strerror(errno));
+                                               ast_hangup(chan);
+                                               return 1;
+                                       }
+                                       break;
+                               }
+                               if (analog_p->ringt)
+                                       analog_p->ringt--;
+                               if (analog_p->ringt == 1) {
+                                       res = -1;
+                                       break;
+                               }
+                       }
+               }
+       }
+       if ((checkaftercid && usedistinctiveringdetection) || !checkaftercid) {
+               /* this only shows up if you have n of the dring patterns filled in */
+               ast_verb(3, "Detected ring pattern: %d,%d,%d\n",ringdata[0],ringdata[1],ringdata[2]);
+               for (counter = 0; counter < 3; counter++) {
+               /* Check to see if the rings we received match any of the ones in chan_dahdi.conf for this channel */
+                       distMatches = 0;
+                       /* this only shows up if you have n of the dring patterns filled in */
+                       ast_verb(3, "Checking %d,%d,%d\n",
+                                       p->drings.ringnum[counter].ring[0],
+                                       p->drings.ringnum[counter].ring[1],
+                                       p->drings.ringnum[counter].ring[2]);
+                       for (counter1 = 0; counter1 < 3; counter1++) {
+                               ast_verb(3, "Ring pattern check range: %d\n", p->drings.ringnum[counter].range);
+                               if (p->drings.ringnum[counter].ring[counter1] == -1) {
+                                       ast_verb(3, "Pattern ignore (-1) detected, so matching pattern %d regardless.\n",
+                                       ringdata[counter1]);
+                                       distMatches++;
+                               } else if (ringdata[counter1] <= (p->drings.ringnum[counter].ring[counter1] + p->drings.ringnum[counter].range) &&
+                                                                               ringdata[counter1] >= (p->drings.ringnum[counter].ring[counter1] - p->drings.ringnum[counter].range)) {
+                                       ast_verb(3, "Ring pattern matched in range: %d to %d\n",
+                                       (p->drings.ringnum[counter].ring[counter1] - p->drings.ringnum[counter].range),
+                                       (p->drings.ringnum[counter].ring[counter1] + p->drings.ringnum[counter].range));
+                                       distMatches++;
+                               }
+                       }
+
+                       if (distMatches == 3) {
+                               /* The ring matches, set the context to whatever is for distinctive ring.. */
+                               ast_copy_string(p->context, p->drings.ringContext[counter].contextData, sizeof(p->context));
+                               ast_copy_string(chan->context, p->drings.ringContext[counter].contextData, sizeof(chan->context));
+                               ast_verb(3, "Distinctive Ring matched context %s\n",p->context);
+                               break;
+                       }
+               }
+       }
+       /* Restore linear mode (if appropriate) for Caller*ID processing */
+       dahdi_setlinear(p->subs[idx].dfd, p->subs[idx].linear);
+       restore_gains(p);
+
+       return 0;
 }
 
 static int send_callerid(struct dahdi_pvt *p);
@@ -1656,7 +1820,7 @@ static int my_send_callerid(void *pvt, int cwcid, struct ast_callerid *cid)
 {
        struct dahdi_pvt *p = pvt;
 
-       ast_log(LOG_ERROR, "Starting cid spill\n");
+       ast_debug(2, "Starting cid spill\n");
 
        if (p->cidspill) {
                ast_log(LOG_WARNING, "cidspill already exists??\n");
@@ -1809,17 +1973,66 @@ static void my_handle_dtmfup(void *pvt, struct ast_channel *ast, enum analog_sub
 static void my_lock_private(void *pvt)
 {
        struct dahdi_pvt *p = pvt;
-
        ast_mutex_lock(&p->lock);
 }
 
 static void my_unlock_private(void *pvt)
 {
        struct dahdi_pvt *p = pvt;
-
        ast_mutex_unlock(&p->lock);
 }
 
+static int my_set_linear_mode(void *pvt, int idx, int linear_mode)
+{
+       struct dahdi_pvt *p = pvt;
+       if (!linear_mode)
+               linear_mode = p->subs[idx].linear;
+       return dahdi_setlinear(p->subs[idx].dfd, linear_mode);
+}
+
+static int get_alarms(struct dahdi_pvt *p);
+static void handle_alarms(struct dahdi_pvt *p, int alms);
+static void my_get_and_handle_alarms(void *pvt)
+{
+       int res;
+       struct dahdi_pvt *p = pvt;
+       
+       res = get_alarms(p);
+       handle_alarms(p, res);
+}
+
+static void *my_get_sigpvt_bridged_channel(struct ast_channel *chan)
+{
+       struct dahdi_pvt *p = ast_bridged_channel(chan)->tech_pvt;
+       if (p)
+               return p->sig_pvt;
+       else
+               return NULL;
+}
+
+static int my_get_sub_fd(void *pvt, enum analog_sub sub)
+{
+       struct dahdi_pvt *p = pvt;
+       int dahdi_sub = analogsub_to_dahdisub(sub);
+       return p->subs[dahdi_sub].dfd;
+}
+
+static void my_set_cadence(void *pvt, int *cidrings, struct ast_channel *ast)
+{
+       struct dahdi_pvt *p = pvt;
+
+       /* Choose proper cadence */
+       if ((p->distinctivering > 0) && (p->distinctivering <= num_cadence)) {
+               if (ioctl(p->subs[SUB_REAL].dfd, DAHDI_SETCADENCE, &cadences[p->distinctivering - 1]))
+                       ast_log(LOG_WARNING, "Unable to set distinctive ring cadence %d on '%s': %s\n", p->distinctivering, ast->name, strerror(errno));
+               *cidrings = cidrings[p->distinctivering - 1];
+       } else {
+               if (ioctl(p->subs[SUB_REAL].dfd, DAHDI_SETCADENCE, NULL))
+                       ast_log(LOG_WARNING, "Unable to reset default ring on '%s': %s\n", ast->name, strerror(errno));
+               *cidrings = p->sendcalleridafter;
+       }
+}
+
 static void my_increase_ss_count(void)
 {
        ast_mutex_lock(&ss_thread_lock);
@@ -2189,6 +2402,13 @@ static int my_ring(void *pvt)
        return dahdi_ring_phone(p);
 }
 
+static int my_flash(void *pvt)
+{
+       struct dahdi_pvt *p = pvt;
+       int func = DAHDI_FLASH;
+       return ioctl(p->subs[SUB_REAL].dfd, DAHDI_HOOK, &func);
+}
+
 static inline int dahdi_set_hook(int fd, int hs);
 
 static int my_off_hook(void *pvt)
@@ -2263,9 +2483,7 @@ static int my_is_dialing(void *pvt, enum analog_sub sub)
 static int my_on_hook(void *pvt)
 {
        struct dahdi_pvt *p = pvt;
-       int x = DAHDI_ONHOOK;
-
-       return ioctl(p->subs[ANALOG_SUB_REAL].dfd, DAHDI_HOOK, &x);
+       return dahdi_set_hook(p->subs[ANALOG_SUB_REAL].dfd, DAHDI_ONHOOK);
 }
 
 #ifdef HAVE_PRI
@@ -2317,8 +2535,6 @@ static int sig_pri_tone_to_dahditone(enum analog_tone tone)
        }
 }
 
-static const char *event2str(int event);
-
 static void my_handle_dchan_exception(struct sig_pri_pri *pri, int index)
 {
        int x, res;
@@ -2433,6 +2649,7 @@ static struct analog_callback dahdi_analog_callbacks =
        .is_off_hook = my_is_off_hook,
        .set_echocanceller = my_set_echocanceller,
        .ring = my_ring,
+       .flash = my_flash,
        .off_hook = my_off_hook,
        .dial_digits = my_dial_digits,
        .train_echocanceller = my_train_echocanceller,
@@ -2464,6 +2681,12 @@ static struct analog_callback dahdi_analog_callbacks =
        .handle_notify_message = my_handle_notify_message,
        .increase_ss_count = my_increase_ss_count,
        .decrease_ss_count = my_decrease_ss_count,
+       .distinctive_ring = my_distinctive_ring,
+       .set_linear_mode = my_set_linear_mode,
+       .get_and_handle_alarms = my_get_and_handle_alarms,
+       .get_sigpvt_bridged_channel = my_get_sigpvt_bridged_channel,
+       .get_sub_fd = my_get_sub_fd,
+       .set_cadence = my_set_cadence,
 };
 
 static struct dahdi_pvt *round_robin[32];
@@ -2492,36 +2715,6 @@ static inline int ss7_grab(struct dahdi_pvt *pvt, struct dahdi_ss7 *pri)
        return 0;
 }
 #endif /* defined(HAVE_SS7) */
-#define NUM_CADENCE_MAX 25
-static int num_cadence = 4;
-static int user_has_defined_cadences = 0;
-
-static struct dahdi_ring_cadence cadences[NUM_CADENCE_MAX] = {
-       { { 125, 125, 2000, 4000 } },                   /*!< Quick chirp followed by normal ring */
-       { { 250, 250, 500, 1000, 250, 250, 500, 4000 } }, /*!< British style ring */
-       { { 125, 125, 125, 125, 125, 4000 } },  /*!< Three short bursts */
-       { { 1000, 500, 2500, 5000 } },  /*!< Long ring */
-};
-
-/*! \brief cidrings says in which pause to transmit the cid information, where the first pause
- * is 1, the second pause is 2 and so on.
- */
-
-static int cidrings[NUM_CADENCE_MAX] = {
-       2,                                                                              /*!< Right after first long ring */
-       4,                                                                              /*!< Right after long part */
-       3,                                                                              /*!< After third chirp */
-       2,                                                                              /*!< Second spell */
-};
-
-/* ETSI EN300 659-1 specifies the ring pulse between 200 and 300 mS */
-static struct dahdi_ring_cadence AS_RP_cadence = {{250, 10000}};
-
-#define ISTRUNK(p) ((p->sig == SIG_FXSLS) || (p->sig == SIG_FXSKS) || \
-                       (p->sig == SIG_FXSGS) || (p->sig == SIG_PRI))
-
-#define CANBUSYDETECT(p) (ISTRUNK(p) || (p->sig & (SIG_EM | SIG_EM_E1 | SIG_SF)) /* || (p->sig & __DAHDI_SIG_FXO) */)
-#define CANPROGRESSDETECT(p) (ISTRUNK(p) || (p->sig & (SIG_EM | SIG_EM_E1 | SIG_SF)) /* || (p->sig & __DAHDI_SIG_FXO) */)
 
 static int dahdi_get_index(struct ast_channel *ast, struct dahdi_pvt *p, int nullok)
 {
@@ -2673,8 +2866,6 @@ static void dahdi_r2_on_call_init(openr2_chan_t *r2chan)
        ast_log(LOG_NOTICE, "New MFC/R2 call detected on chan %d.\n", openr2_chan_get_number(r2chan));
 }
 
-static int get_alarms(struct dahdi_pvt *p);
-static void handle_alarms(struct dahdi_pvt *p, int alms);
 static void dahdi_r2_on_hardware_alarm(openr2_chan_t *r2chan, int alarm)
 {
        int res;
@@ -3051,8 +3242,6 @@ static openr2_transcoder_interface_t dahdi_r2_transcode_iface = {
 
 #endif /* HAVE_OPENR2 */
 
-static int restore_gains(struct dahdi_pvt *p);
-
 static void swap_subs(struct dahdi_pvt *p, int a, int b)
 {
        int tchan;
@@ -4111,29 +4300,6 @@ static int dahdi_call(struct ast_channel *ast, char *rdest, int timeout)
        }
 #endif
 
-       /* Set the ring cadence */
-       mysig = p->sig;
-       if (p->outsigmod > -1)
-               mysig = p->outsigmod;
-       switch (mysig) {
-       case SIG_FXOLS:
-       case SIG_FXOGS:
-       case SIG_FXOKS:
-               if (p->owner == ast) {
-                       /* Choose proper cadence */
-                       if ((p->distinctivering > 0) && (p->distinctivering <= num_cadence)) {
-                               if (ioctl(p->subs[SUB_REAL].dfd, DAHDI_SETCADENCE, &cadences[p->distinctivering - 1]))
-                                       ast_log(LOG_WARNING, "Unable to set distinctive ring cadence %d on '%s': %s\n", p->distinctivering, ast->name, strerror(errno));
-                               p->cidrings = cidrings[p->distinctivering - 1];
-                       } else {
-                               if (ioctl(p->subs[SUB_REAL].dfd, DAHDI_SETCADENCE, NULL))
-                                       ast_log(LOG_WARNING, "Unable to reset default ring on '%s': %s\n", ast->name, strerror(errno));
-                               p->cidrings = p->sendcalleridafter;
-                       }
-               }
-               break;
-       }
-
        /* If this is analog signalling we can exit here */
        if (analog_lib_handles(p->sig, p->radio, p->oprmode)) {
                p->callwaitrings = 0;
@@ -4142,6 +4308,7 @@ static int dahdi_call(struct ast_channel *ast, char *rdest, int timeout)
                return res;
        }
 
+       mysig = p->outsigmod > -1 ? p->outsigmod : p->sig;
        switch (mysig) {
        case 0:
                /* Special pseudo -- automatically up*/
@@ -4877,12 +5044,10 @@ static int dahdi_hangup(struct ast_channel *ast)
                p->ringt = 0;
                p->distinctivering = 0;
                p->confirmanswer = 0;
-               p->cidrings = 1;
                p->outgoing = 0;
                p->digital = 0;
                p->faxhandled = 0;
                p->pulsedial = 0;
-               p->onhooktime = time(NULL);
 #if defined(HAVE_PRI) || defined(HAVE_SS7)
                p->proceeding = 0;
                p->dialing = 0;
@@ -4970,6 +5135,7 @@ static int dahdi_hangup(struct ast_channel *ast)
                        memset(&par, 0, sizeof(par));
                        res = ioctl(p->subs[SUB_REAL].dfd, DAHDI_GET_PARAMS, &par);
                        if (!res) {
+                               struct analog_pvt *analog_p = p->sig_pvt;
 #if 0
                                ast_debug(1, "Hanging up channel %d, offhook = %d\n", p->channel, par.rxisoffhook);
 #endif
@@ -4978,14 +5144,14 @@ static int dahdi_hangup(struct ast_channel *ast)
                                        tone_zone_play_tone(p->subs[SUB_REAL].dfd, DAHDI_TONE_CONGESTION);
                                else
                                        tone_zone_play_tone(p->subs[SUB_REAL].dfd, -1);
-                               p->fxsoffhookstate = par.rxisoffhook;
+                               analog_p->fxsoffhookstate = par.rxisoffhook;
                        }
                        break;
                case SIG_FXSGS:
                case SIG_FXSLS:
                case SIG_FXSKS:
                        /* Make sure we're not made available for at least two seconds assuming
-                          we were actually used for an inbound or outbound call. */
+                       we were actually used for an inbound or outbound call. */
                        if (ast->_state != AST_STATE_RESERVED) {
                                time(&p->guardtime);
                                p->guardtime += 2;
@@ -6371,9 +6537,6 @@ static struct ast_frame *dahdi_handle_event(struct ast_channel *ast)
                case SIG_FXOLS:
                case SIG_FXOGS:
                case SIG_FXOKS:
-                       p->onhooktime = time(NULL);
-                       p->fxsoffhookstate = 0;
-                       p->msgstate = -1;
                        /* Check for some special conditions regarding call waiting */
                        if (idx == SUB_REAL) {
                                /* The normal line was hung up */
@@ -6524,7 +6687,6 @@ static struct ast_frame *dahdi_handle_event(struct ast_channel *ast)
                case SIG_FXOLS:
                case SIG_FXOGS:
                case SIG_FXOKS:
-                       p->fxsoffhookstate = 1;
                        switch (ast->_state) {
                        case AST_STATE_RINGING:
                                dahdi_enable_ec(p);
@@ -7324,7 +7486,12 @@ static struct ast_frame *dahdi_read(struct ast_channel *ast)
                                ast_mutex_unlock(&p->lock);
                                return &p->subs[idx].f;
                        } else if (errno == ELAST) {
-                               f = __dahdi_exception(ast);
+                               if (analog_lib_handles(p->sig, p->radio, p->oprmode)) {
+                                       struct analog_pvt *analog_p = p->sig_pvt;
+                                       f = analog_exception(analog_p, ast);
+                               } else {
+                                       f = __dahdi_exception(ast);
+                               }
                        } else
                                ast_log(LOG_WARNING, "dahdi_rec: %s\n", strerror(errno));
                }
@@ -7333,7 +7500,12 @@ static struct ast_frame *dahdi_read(struct ast_channel *ast)
        }
        if (res != (p->subs[idx].linear ? READ_SIZE * 2 : READ_SIZE)) {
                ast_debug(1, "Short read (%d/%d), must be an event...\n", res, p->subs[idx].linear ? READ_SIZE * 2 : READ_SIZE);
-               f = __dahdi_exception(ast);
+               if (analog_lib_handles(p->sig, p->radio, p->oprmode)) {
+                       struct analog_pvt *analog_p = p->sig_pvt;
+                       f = analog_exception(analog_p, ast);
+               } else {
+                       f = __dahdi_exception(ast);
+               }
                ast_mutex_unlock(&p->lock);
                return f;
        }
@@ -7555,8 +7727,10 @@ static int dahdi_write(struct ast_channel *ast, struct ast_frame *frame)
        if (analog_lib_handles(p->sig, p->radio, p->oprmode)) {
                struct analog_pvt *ap = p->sig_pvt;
 
-               if (ap->dialing)
+               if (ap->dialing) {
+                       ast_debug(1, "Dropping frame since I'm still dialing on %s...\n",ast->name);
                        return 0;
+               }
        }
        if (p->dialing) {
                ast_debug(1, "Dropping frame since I'm still dialing on %s...\n",ast->name);
@@ -8934,8 +9108,9 @@ static void *analog_ss_thread(void *data)
                                                                }
                                                                break;
                                                        }
-                                                       if (p->ringt)
+                                                       if (p->ringt) {
                                                                p->ringt--;
+                                                       }
                                                        if (p->ringt == 1) {
                                                                res = -1;
                                                                break;
@@ -9488,7 +9663,6 @@ static int handle_init_event(struct dahdi_pvt *i, int event)
                case SIG_FXOGS:
                case SIG_FXOKS:
                        res = dahdi_set_hook(i->subs[SUB_REAL].dfd, DAHDI_OFFHOOK);
-                       i->fxsoffhookstate = 1;
                        if (res && (errno == EBUSY))
                                break;
                        if (i->cidspill) {
@@ -9636,9 +9810,6 @@ static int handle_init_event(struct dahdi_pvt *i, int event)
                        res = tone_zone_play_tone(i->subs[SUB_REAL].dfd, -1);
                        return -1;
                }
-               if (i->sig & __DAHDI_SIG_FXO) {
-                       i->fxsoffhookstate = 0;
-               }
                break;
        case DAHDI_EVENT_POLARITY:
                switch (i->sig) {
@@ -9801,12 +9972,13 @@ static void *do_monitor(void *data)
                                if (!found && ((i == last) || ((i == iflist) && !last))) {
                                        last = i;
                                        if (last) {
+                                               struct analog_pvt *analog_p = last->sig_pvt;
                                                /* Only allow MWI to be initiated on a quiescent fxs port */
                                                if (!last->mwisendactive &&     last->sig & __DAHDI_SIG_FXO &&
-                                                               !last->fxsoffhookstate && !last->owner &&
-                                                               !ast_strlen_zero(last->mailbox) && (thispass - last->onhooktime > 3)) {
+                                                               !analog_p->fxsoffhookstate && !last->owner &&
+                                                               !ast_strlen_zero(last->mailbox) && (thispass - analog_p->onhooktime > 3)) {
                                                        res = has_voicemail(last);
-                                                       if (last->msgstate != res) {
+                                                       if (analog_p->msgstate != res) {
                                                                /* Set driver resources for signalling VMWI */
                                                                res2 = ioctl(last->subs[SUB_REAL].dfd, DAHDI_VMWI, &res);
                                                                if (res2) {
@@ -9817,7 +9989,7 @@ static void *do_monitor(void *data)
                                                                if (mwi_send_init(last)) {
                                                                        ast_log(LOG_WARNING, "Unable to initiate mwi send sequence on channel %d\n", last->channel);
                                                                }
-                                                               last->msgstate = res;
+                                                               analog_p->msgstate = res;
                                                                found ++;
                                                        }
                                                }
@@ -10746,23 +10918,12 @@ static struct dahdi_pvt *mkintf(int channel, const struct dahdi_chan_conf *conf,
                                AST_EVENT_IE_NEWMSGS, AST_EVENT_IE_PLTYPE_EXISTS,
                                AST_EVENT_IE_END);
                }
-               tmp->msgstate = -1;
 #ifdef HAVE_DAHDI_LINEREVERSE_VMWI
                tmp->mwisend_setting = conf->chan.mwisend_setting;
                tmp->mwisend_fsk  = conf->chan.mwisend_fsk;
                tmp->mwisend_rpas = conf->chan.mwisend_rpas;
 #endif
-               if (chan_sig & __DAHDI_SIG_FXO) {
-                       memset(&p, 0, sizeof(p));
-                       res = ioctl(tmp->subs[SUB_REAL].dfd, DAHDI_GET_PARAMS, &p);
-                       if (!res) {
-                               tmp->fxsoffhookstate = p.rxisoffhook;
-                       }
-#ifdef HAVE_DAHDI_LINEREVERSE_VMWI
-                       res = ioctl(tmp->subs[SUB_REAL].dfd, DAHDI_VMWI_CONFIG, &tmp->mwisend_setting);
-#endif
-               }
-               tmp->onhooktime = time(NULL);
+               
                tmp->group = conf->chan.group;
                tmp->callgroup = conf->chan.callgroup;
                tmp->pickupgroup= conf->chan.pickupgroup;
@@ -10841,7 +11002,6 @@ static struct dahdi_pvt *mkintf(int channel, const struct dahdi_chan_conf *conf,
                                analog_p->polarityonanswerdelay = conf->chan.polarityonanswerdelay;
                                analog_p->answeronpolarityswitch = conf->chan.answeronpolarityswitch;
                                analog_p->hanguponpolarityswitch = conf->chan.hanguponpolarityswitch;
-                               analog_p->sendcalleridafter = conf->chan.sendcalleridafter;
                                analog_p->permcallwaiting = 1;
                                analog_p->callreturn = conf->chan.callreturn;
                                analog_p->cancallforward = conf->chan.cancallforward;
@@ -10860,7 +11020,23 @@ static struct dahdi_pvt *mkintf(int channel, const struct dahdi_chan_conf *conf,
                                analog_p->stripmsd = conf->chan.stripmsd;
                                analog_p->cid_start = ANALOG_CID_START_RING;
                                tmp->callwaitingcallerid = analog_p->callwaitingcallerid = 1;
-       
+                               analog_p->usedistinctiveringdetection = conf->chan.usedistinctiveringdetection;
+                               analog_p->ringt = conf->chan.ringt;
+                               analog_p->ringt_base = ringt_base;
+                               analog_p->chan_tech = &dahdi_tech;
+                               analog_p->onhooktime = time(NULL);
+                               if (chan_sig & __DAHDI_SIG_FXO) {
+                                       memset(&p, 0, sizeof(p));
+                                       res = ioctl(tmp->subs[SUB_REAL].dfd, DAHDI_GET_PARAMS, &p);
+                                       if (!res) {
+                                               analog_p->fxsoffhookstate = p.rxisoffhook;
+                                       }
+#ifdef HAVE_DAHDI_LINEREVERSE_VMWI
+                                       res = ioctl(tmp->subs[SUB_REAL].dfd, DAHDI_VMWI_CONFIG, &tmp->mwisend_setting);
+#endif
+                               }
+                               analog_p->msgstate = -1;
+
                                ast_copy_string(analog_p->mohsuggest, conf->chan.mohsuggest, sizeof(analog_p->mohsuggest));
                                ast_copy_string(analog_p->cid_num, conf->chan.cid_num, sizeof(analog_p->cid_num));
                                ast_copy_string(analog_p->cid_name, conf->chan.cid_name, sizeof(analog_p->cid_name));
index e397e5f..e62eb04 100644 (file)
@@ -38,6 +38,7 @@
 #include "asterisk/astdb.h"
 #include "asterisk/features.h"
 #include "asterisk/cel.h"
+#include "asterisk/causes.h"
 
 #include "sig_analog.h"
 
@@ -89,6 +90,9 @@ static const struct {
         * way to do this in the dialplan now. */
 };
 
+#define ISTRUNK(p) ((p->sig == ANALOG_SIG_FXSLS) || (p->sig == ANALOG_SIG_FXSKS) || \
+                                       (p->sig == ANALOG_SIG_FXSGS))
+
 enum analog_sigtype analog_str_to_sigtype(const char *name)
 {
        int i;
@@ -397,6 +401,14 @@ static int analog_ring(struct analog_pvt *p)
                return -1;
 }
 
+static int analog_flash(struct analog_pvt *p)
+{
+       if (p->calls->flash)
+               return p->calls->flash(p->chan_pvt);
+       else
+               return -1;
+}
+
 static int analog_start(struct analog_pvt *p)
 {
        if (p->calls->start)
@@ -676,6 +688,13 @@ static int analog_callwait(struct analog_pvt *p)
                return 0;
 }
 
+static void analog_set_cadence(struct analog_pvt *p, struct ast_channel *chan)
+{
+       if (p->calls->set_cadence) {
+               return p->calls->set_cadence(p->chan_pvt, &p->cidrings, chan);
+       }
+}
+
 int analog_call(struct analog_pvt *p, struct ast_channel *ast, char *rdest, int timeout)
 {
        int res, index,mysig;
@@ -712,20 +731,7 @@ int analog_call(struct analog_pvt *p, struct ast_channel *ast, char *rdest, int
 
                        /* Don't send audio while on hook, until the call is answered */
                        p->dialing = 1;
-                       /* XXX */
-#if 0
-                       /* Choose proper cadence */
-                       if ((p->distinctivering > 0) && (p->distinctivering <= num_cadence)) {
-                               if (ioctl(p->subs[ANALOG_SUB_REAL].dfd, DAHDI_SETCADENCE, &cadences[p->distinctivering - 1]))
-                                       ast_log(LOG_WARNING, "Unable to set distinctive ring cadence %d on '%s': %s\n", p->distinctivering, ast->name, strerror(errno));
-                               p->cidrings = cidrings[p->distinctivering - 1];
-                       } else {
-                               if (ioctl(p->subs[ANALOG_SUB_REAL].dfd, DAHDI_SETCADENCE, NULL))
-                                       ast_log(LOG_WARNING, "Unable to reset default ring on '%s': %s\n", ast->name, strerror(errno));
-                               p->cidrings = p->sendcalleridafter;
-                       }
-#endif
-                       p->cidrings = p->sendcalleridafter;
+                       analog_set_cadence(p, ast); /* and set p->cidrings */
 
                        /* nick@dccinc.com 4/3/03 mods to allow for deferred dialing */
                        c = strchr(dest, '/');
@@ -1042,13 +1048,10 @@ int analog_hangup(struct analog_pvt *p, struct ast_channel *ast)
 
        if (!p->subs[ANALOG_SUB_REAL].owner && !p->subs[ANALOG_SUB_CALLWAIT].owner && !p->subs[ANALOG_SUB_THREEWAY].owner) {
                p->owner = NULL;
-#if 0
                p->ringt = 0;
-#endif
-#if 0 /* Since we set it in _call */
-               p->cidrings = 1;
-#endif
                p->outgoing = 0;
+               p->onhooktime = time(NULL);
+               p->cidrings = 1;
 
                /* Perform low level hangup if no owner left */
                res = analog_on_hook(p);
@@ -1115,9 +1118,7 @@ int analog_answer(struct analog_pvt *p, struct ast_channel *ast)
        case ANALOG_SIG_FXSLS:
        case ANALOG_SIG_FXSGS:
        case ANALOG_SIG_FXSKS:
-#if 0
                p->ringt = 0;
-#endif
                /* Fall through */
        case ANALOG_SIG_EM:
        case ANALOG_SIG_EM_E1:
@@ -1259,13 +1260,47 @@ static int analog_decrease_ss_count(struct analog_pvt *p)
                return -1;
 }
 
+static int analog_distinctive_ring(struct ast_channel *chan, struct analog_pvt *p, int idx, int *ringdata)
+{
+       if (p->calls->distinctive_ring) {
+               return p->calls->distinctive_ring(chan, p->chan_pvt, idx, ringdata);
+       } else
+               return -1;
+
+}
+
+static int analog_set_linear_mode(struct analog_pvt *p, int index, int linear_mode)
+{
+       if (p->calls->set_linear_mode) {
+               return p->calls->set_linear_mode(p->chan_pvt, index, linear_mode);
+       } else
+               return -1;
+}
+
+static void analog_get_and_handle_alarms(struct analog_pvt *p)
+{
+       if (p->calls->get_and_handle_alarms)
+               return p->calls->get_and_handle_alarms(p->chan_pvt);
+}
+
+static void *analog_get_bridged_channel(struct analog_pvt *p, struct ast_channel *chan)
+{
+       if (p->calls->get_sigpvt_bridged_channel)
+               return p->calls->get_sigpvt_bridged_channel;
+       else
+               return NULL;
+}
+
+static int analog_get_sub_fd(struct analog_pvt *p, enum analog_sub sub)
+{
+       if (p->calls->get_sub_fd) {
+               return p->calls->get_sub_fd(p->chan_pvt, sub);
+       } else
+               return -1;
+}
+
 #define ANALOG_NEED_MFDETECT(p) (((p)->sig == ANALOG_SIG_FEATDMF) || ((p)->sig == ANALOG_SIG_FEATDMF_TA) || ((p)->sig == ANALOG_SIG_E911) || ((p)->sig == ANALOG_SIG_FGC_CAMA) || ((p)->sig == ANALOG_SIG_FGC_CAMAMF) || ((p)->sig == ANALOG_SIG_FEATB))
 
-/* Note by jpeeler: This function has a rather large section of code ifdefed
- * away. I'd like to leave the code there until more testing is done and I
- * know for sure that nothing got left out. The plan is at the latest for this
- * comment and code below to be removed shortly after the merging of sig_pri.
- */
 static void *__analog_ss_thread(void *data)
 {
        struct analog_pvt *p = data;
@@ -1279,16 +1314,6 @@ static void *__analog_ss_thread(void *data)
        struct callerid_state *cs = NULL;
        char *name = NULL, *number = NULL;
        int flags;
-#if 0
-       unsigned char buf[256];
-       int distMatches;
-       int curRingData[3];
-       int receivedRingT;
-       int samples = 0;
-       int counter1;
-       int counter;
-       int i;
-#endif
        int timeout;
        int getforward = 0;
        char *s1, *s2;
@@ -1794,21 +1819,19 @@ static void *__analog_ss_thread(void *data)
                                memset(exten, 0, sizeof(exten));
                                timeout = analog_firstdigittimeout;
                        } else if (!strcmp(exten, "*0")) {
-#ifdef XXX
                                struct ast_channel *nbridge = p->subs[ANALOG_SUB_THREEWAY].owner;
-                               struct dahdi_pvt *pbridge = NULL;
+                               struct analog_pvt *pbridge = NULL;
                                  /* set up the private struct of the bridged one, if any */
                                if (nbridge && ast_bridged_channel(nbridge))
-                                       pbridge = ast_bridged_channel(nbridge)->tech_pvt;
+                                       pbridge = analog_get_bridged_channel(p, nbridge);
                                if (nbridge && pbridge &&
-                                   (nbridge->tech == chan_tech) &&
-                                   (ast_bridged_channel(nbridge)->tech == chan_tech) &&
+                                   (nbridge->tech == p->chan_tech) &&
+                                   (ast_bridged_channel(nbridge)->tech == p->chan_tech) &&
                                    ISTRUNK(pbridge)) {
-                                       int func = DAHDI_FLASH;
                                        /* Clear out the dial buffer */
                                        p->dop.dialstr[0] = '\0';
                                        /* flash hookswitch */
-                                       if ((ioctl(pbridge->subs[ANALOG_SUB_REAL].dfd,DAHDI_HOOK,&func) == -1) && (errno != EINPROGRESS)) {
+                                       if ((analog_flash(p) == -1) && (errno != EINPROGRESS)) {
                                                ast_log(LOG_WARNING, "Unable to flash external trunk on channel %s: %s\n",
                                                        nbridge->name, strerror(errno));
                                        }
@@ -1829,7 +1852,6 @@ static void *__analog_ss_thread(void *data)
                                        ast_hangup(chan);
                                        goto quit;
                                }
-#endif
                        } else if (!ast_canmatch_extension(chan, chan->context, exten, 1, chan->cid.cid_num) &&
                                                        ((exten[0] != '*') || (strlen(exten) > 2))) {
                                ast_debug(1, "Can't match %s from '%s' in context %s\n", exten, chan->cid.cid_num ? chan->cid.cid_num : "<Unknown Caller>", chan->context);
@@ -1855,9 +1877,9 @@ static void *__analog_ss_thread(void *data)
                                cs = NULL;
                                ast_debug(1, "Receiving DTMF cid on "
                                        "channel %s\n", chan->name);
-#if 0
-                               dahdi_setlinear(p->subs[index].dfd, 0);
-#endif
+
+                               analog_set_linear_mode(p, index, 0);
+
                                res = 2000;
                                for (;;) {
                                        struct ast_frame *f;
@@ -1868,8 +1890,7 @@ static void *__analog_ss_thread(void *data)
                                                ast_hangup(chan);
                                                goto quit;
                                        }
-                                       f = ast_read(chan);
-                                       if (!f)
+                                       if (!(f = ast_read(chan)))
                                                break;
                                        if (f->frametype == AST_FRAME_DTMF) {
                                                dtmfbuf[i++] = f->subclass;
@@ -1882,9 +1903,9 @@ static void *__analog_ss_thread(void *data)
                                                break; /* Got ring */
                                }
                                dtmfbuf[i] = '\0';
-#if 0
-                               dahdi_setlinear(p->subs[index].dfd, p->subs[index].linear);
-#endif
+
+                               analog_set_linear_mode(p, index, 1);
+
                                /* Got cid and ring. */
                                ast_debug(1, "CID got string '%s'\n", dtmfbuf);
                                callerid_get_dtmf(dtmfbuf, dtmfcid, &flags);
@@ -1895,82 +1916,51 @@ static void *__analog_ss_thread(void *data)
                                        number = dtmfcid;
                                else
                                        number = NULL;
-#if 0
+
                        /* If set to use V23 Signalling, launch our FSK gubbins and listen for it */
                        } else if ((p->cid_signalling == CID_SIG_V23) || (p->cid_signalling == CID_SIG_V23_JP)) {
-                               cs = callerid_new(p->cid_signalling);
-                               if (cs) {
-                                       samples = 0;
-#if 1
-                                       bump_gains(p);
-#endif                         
-                                       /* Take out of linear mode for Caller*ID processing */
-                                       dahdi_setlinear(p->subs[index].dfd, 0);
-                                       
-                                       /* First we wait and listen for the Caller*ID */
-                                       for (;;) {      
-                                               i = DAHDI_IOMUX_READ | DAHDI_IOMUX_SIGEVENT;
-                                               if ((res = ioctl(p->subs[index].dfd, DAHDI_IOMUX, &i))) {
-                                                       ast_log(LOG_WARNING, "I/O MUX failed: %s\n", strerror(errno));
-                                                       callerid_free(cs);
-                                                       ast_hangup(chan);
-                                                       goto quit;
+                               int timeout = 10000;  /* Ten seconds */
+                               struct timeval start = ast_tvnow();
+                               enum analog_event ev;
+
+                               namebuf[0] = 0;
+                               numbuf[0] = 0;
+
+                               if (!analog_start_cid_detect(p, p->cid_signalling)) {
+                                       while (1) {
+                                               res = analog_get_callerid(p, namebuf, numbuf, &ev, timeout - ast_tvdiff_ms(ast_tvnow(), start));
+       
+                                               if (res == 0) {
+                                                       break;
                                                }
-                                               if (i & DAHDI_IOMUX_SIGEVENT) {
-                                                       res = dahdi_get_event(p->subs[index].dfd);
-                                                       ast_log(LOG_NOTICE, "Got event %d (%s)...\n", res, event2str(res));
 
+                                               if (res == 1) {
                                                        if (p->cid_signalling == CID_SIG_V23_JP) {
-#ifdef DAHDI_EVENT_RINGBEGIN
-                                                               if (res == ANALOG_EVENT_RINGBEGIN) {
-                                                                       res = analog_off_hook(p);
+                                                               if (ev == ANALOG_EVENT_RINGBEGIN) {
+                                                                       analog_off_hook(p);
                                                                        usleep(1);
-                                                               }
-#endif
+                                                               } 
                                                        } else {
-                                                               res = 0;
+                                                               ev = ANALOG_EVENT_NONE;
                                                                break;
                                                        }
-                                               } else if (i & DAHDI_IOMUX_READ) {
-                                                       res = read(p->subs[index].dfd, buf, sizeof(buf));
-                                                       if (res < 0) {
-                                                               if (errno != ELAST) {
-                                                                       ast_log(LOG_WARNING, "read returned error: %s\n", strerror(errno));
-                                                                       callerid_free(cs);
-                                                                       ast_hangup(chan);
-                                                                       goto quit;
-                                                               }
-                                                               break;
-                                                       }
-                                                       samples += res;
-
-                                                       if  (p->cid_signalling == CID_SIG_V23_JP) {
-                                                               res = callerid_feed_jp(cs, buf, res, AST_LAW(p));
-                                                       } else {
-                                                               res = callerid_feed(cs, buf, res, AST_LAW(p));
-                                                       }
-
-                                                       if (res < 0) {
-                                                               ast_log(LOG_WARNING, "CallerID feed failed on channel '%s'\n", chan->name);
-                                                               break;
-                                                       } else if (res)
-                                                               break;
-                                                       else if (samples > (8000 * 10))
-                                                               break;
                                                }
+       
+                                               if (ast_tvdiff_ms(ast_tvnow(), start) > timeout)
+                                                       break;
+       
                                        }
-                                       if (res == 1) {
-                                               callerid_get(cs, &name, &number, &flags);
-                                               ast_log(LOG_NOTICE, "CallerID number: %s, name: %s, flags=%d\n", number, name, flags);
-                                       }
+                                       name = namebuf;
+                                       number = numbuf;
+       
+                                       analog_stop_cid_detect(p);
 
                                        if (p->cid_signalling == CID_SIG_V23_JP) {
                                                res = analog_on_hook(p);
                                                usleep(1);
                                                res = 4000;
                                        } else {
-
-                                               /* Finished with Caller*ID, now wait for a ring to make sure there really is a call coming */ 
+                                               /* Finished with Caller*ID, now wait for a ring to make sure there really is a call coming */
                                                res = 2000;
                                        }
 
@@ -1982,7 +1972,7 @@ static void *__analog_ss_thread(void *data)
                                                                "Exiting simple switch\n");
                                                        ast_hangup(chan);
                                                        goto quit;
-                                               } 
+                                               }
                                                if (!(f = ast_read(chan))) {
                                                        ast_log(LOG_WARNING, "Hangup received waiting for ring. Exiting simple switch\n");
                                                        ast_hangup(chan);
@@ -1990,18 +1980,19 @@ static void *__analog_ss_thread(void *data)
                                                }
                                                ast_frfree(f);
                                                if (chan->_state == AST_STATE_RING ||
-                                                   chan->_state == AST_STATE_RINGING) 
+                                                       chan->_state == AST_STATE_RINGING)
                                                        break; /* Got ring */
                                        }
+
+                                       if (analog_distinctive_ring(chan, p, index, NULL))
+                                               goto quit;
        
-                                       /* Restore linear mode (if appropriate) for Caller*ID processing */
-                                       dahdi_setlinear(p->subs[index].dfd, p->subs[index].linear);
-#if 1
-                                       restore_gains(p);
-#endif                         
+                                       if (res < 0) {
+                                               ast_log(LOG_WARNING, "CallerID returned with error on channel '%s'\n", chan->name);
+                                       }
                                } else
-                                       ast_log(LOG_WARNING, "Unable to get caller ID space\n");                        
-#endif
+                                       ast_log(LOG_WARNING, "Unable to get caller ID space\n");
+
                        } else {
                                ast_log(LOG_WARNING, "Channel %s in prering "
                                        "state, but I have nothing to do. "
@@ -2015,6 +2006,8 @@ static void *__analog_ss_thread(void *data)
                        int timeout = 10000;  /* Ten seconds */
                        struct timeval start = ast_tvnow();
                        enum analog_event ev;
+                       int curRingData[3] = { 0 };
+                       int receivedRingT = 0;
 
                        namebuf[0] = 0;
                        numbuf[0] = 0;
@@ -2027,19 +2020,33 @@ static void *__analog_ss_thread(void *data)
                                                break;
                                        }
 
-                                       if (res == 1) {
+                                       if (res == 1 || res == 2) {
                                                if (ev == ANALOG_EVENT_POLARITY && p->hanguponpolarityswitch && p->polarity == POLARITY_REV) {
                                                        ast_debug(1, "Hanging up due to polarity reversal on channel %d while detecting callerid\n", p->channel);
                                                        p->polarity = POLARITY_IDLE;
                                                        ast_hangup(chan);
                                                        goto quit;
-                                               } else if (ev != ANALOG_EVENT_NONE) {
+                                               } else if (ev != ANALOG_EVENT_NONE && ev != ANALOG_EVENT_RINGBEGIN && ev != ANALOG_EVENT_RINGOFFHOOK) { 
                                                        break;
                                                }
+                                               if (res != 2) {
+                                                       /* Let us detect callerid when the telco uses distinctive ring */
+                                                       curRingData[receivedRingT] = p->ringt;
+
+                                                       if (p->ringt < p->ringt_base/2) {
+                                                               break;
+                                                       }
+                                                       /* Increment the ringT counter so we can match it against
+                                                          values in chan_dahdi.conf for distinctive ring */
+                                                       if (++receivedRingT == ARRAY_LEN(curRingData)) {
+                                                               break;
+                                                       }
+                                               }
                                        }
 
-                                       if (ast_tvdiff_ms(ast_tvnow(), start) > timeout)
+                                       if (ast_tvdiff_ms(ast_tvnow(), start) > timeout) {
                                                break;
+                                       }
 
                                }
                                name = namebuf;
@@ -2047,108 +2054,14 @@ static void *__analog_ss_thread(void *data)
 
                                analog_stop_cid_detect(p);
 
-#if 0
-                       /* XXX */
-                       if (strcmp(p->context,p->defcontext) != 0) {
-                               ast_copy_string(p->context, p->defcontext, sizeof(p->context));
-                               ast_copy_string(chan->context,p->defcontext,sizeof(chan->context));
-                       }
-
-                       analog_get_callerid(p, name, number);
-                       /* FSK Bell202 callerID */
-                       cs = callerid_new(p->cid_signalling);
-                       if (cs) {
-#if 1
-                               bump_gains(p);
-#endif                         
-                               samples = 0;
-                               len = 0;
-                               distMatches = 0;
-                               /* Clear the current ring data array so we dont have old data in it. */
-                               for (receivedRingT = 0; receivedRingT < (sizeof(curRingData) / sizeof(curRingData[0])); receivedRingT++)
-                                       curRingData[receivedRingT] = 0;
-                               receivedRingT = 0;
-                               counter = 0;
-                               counter1 = 0;
-                               /* Check to see if context is what it should be, if not set to be. */
-
-                               /* Take out of linear mode for Caller*ID processing */
-                               dahdi_setlinear(p->subs[index].dfd, 0);
-                               for (;;) {      
-                                       i = DAHDI_IOMUX_READ | DAHDI_IOMUX_SIGEVENT;
-                                       if ((res = ioctl(p->subs[index].dfd, DAHDI_IOMUX, &i))) {
-                                               ast_log(LOG_WARNING, "I/O MUX failed: %s\n", strerror(errno));
-                                               callerid_free(cs);
-                                               ast_hangup(chan);
-                                               goto quit;
-                                       }
-                                       if (i & DAHDI_IOMUX_SIGEVENT) {
-                                               res = dahdi_get_event(p->subs[index].dfd);
-                                               ast_log(LOG_NOTICE, "Got event %d (%s)...\n", res, event2str(res));
-                                               /* If we get a PR event, they hung up while processing calerid */
-                                               if ( res == ANALOG_EVENT_POLARITY && p->hanguponpolarityswitch && p->polarity == POLARITY_REV) {
-                                                       ast_debug(1, "Hanging up due to polarity reversal on channel %d while detecting callerid\n", p->channel);
-                                                       p->polarity = POLARITY_IDLE;
-                                                       callerid_free(cs);
-                                                       ast_hangup(chan);
-                                                       goto quit;
-                                               }
-                                               res = 0;
-                                               /* Let us detect callerid when the telco uses distinctive ring */
-
-                                               curRingData[receivedRingT] = p->ringt;
+                               if (analog_distinctive_ring(chan, p, index, curRingData))
+                                       goto quit;
 
-                                               if (p->ringt < p->ringt_base/2)
-                                                       break;
-                                               /* Increment the ringT counter so we can match it against
-                                                  values in chan_dahdi.conf for distinctive ring */
-                                               if (++receivedRingT == (sizeof(curRingData) / sizeof(curRingData[0])))
-                                                       break;
-                                       } else if (i & DAHDI_IOMUX_READ) {
-                                               res = read(p->subs[index].dfd, buf, sizeof(buf));
-                                               if (res < 0) {
-                                                       if (errno != ELAST) {
-                                                               ast_log(LOG_WARNING, "read returned error: %s\n", strerror(errno));
-                                                               callerid_free(cs);
-                                                               ast_hangup(chan);
-                                                               goto quit;
-                                                       }
-                                                       break;
-                                               }
-                                               if (p->ringt) 
-                                                       p->ringt--;
-                                               if (p->ringt == 1) {
-                                                       res = -1;
-                                                       break;
-                                               }
-                                               samples += res;
-                                               res = callerid_feed(cs, buf, res, AST_LAW(p));
-                                               if (res < 0) {
-                                                       ast_log(LOG_WARNING, "CallerID feed failed: %s\n", strerror(errno));
-                                                       break;
-                                               } else if (res)
-                                                       break;
-                                               else if (samples > (8000 * 10))
-                                                       break;
-                                       }
-                               }
-                               if (res == 1) {
-                                       callerid_get(cs, &name, &number, &flags);
-                                       ast_debug(1, "CallerID number: %s, name: %s, flags=%d\n", number, name, flags);
-                               }
-                               /* Restore linear mode (if appropriate) for Caller*ID processing */
-                               dahdi_setlinear(p->subs[index].dfd, p->subs[index].linear);
-#if 1
-                               restore_gains(p);
-#endif                         
                                if (res < 0) {
                                        ast_log(LOG_WARNING, "CallerID returned with error on channel '%s'\n", chan->name);
                                }
                        } else
                                ast_log(LOG_WARNING, "Unable to get caller ID space\n");
-#endif
-                       } else
-                               ast_log(LOG_WARNING, "Unable to get caller ID space\n");
                }
                else
                        cs = NULL;
@@ -2164,9 +2077,7 @@ static void *__analog_ss_thread(void *data)
 
                ast_setstate(chan, AST_STATE_RING);
                chan->rings = 1;
-#if 0
                p->ringt = p->ringt_base;
-#endif
                res = ast_pbx_run(chan);
                if (res) {
                        ast_hangup(chan);
@@ -2287,15 +2198,16 @@ static struct ast_frame *__analog_handle_event(struct analog_pvt *p, struct ast_
                break;
        case ANALOG_EVENT_ALARM:
                p->inalarm = 1;
-#if 0
-               res = get_alarms(p);
-               handle_alarms(p, res);  
-#endif
+               analog_get_and_handle_alarms(p);
+
        case ANALOG_EVENT_ONHOOK:
                switch (p->sig) {
                case ANALOG_SIG_FXOLS:
                case ANALOG_SIG_FXOGS:
                case ANALOG_SIG_FXOKS:
+                       p->fxsoffhookstate = 0;
+                       p->onhooktime = time(NULL);
+                       p->msgstate = -1;
                        /* Check for some special conditions regarding call waiting */
                        if (index == ANALOG_SUB_REAL) {
                                /* The normal line was hung up */
@@ -2337,7 +2249,7 @@ static struct ast_frame *__analog_handle_event(struct analog_pvt *p, struct ast_
                                                /* It hasn't been long enough since the last flashook.  This is probably a bounce on
                                                   hanging up.  Hangup both channels now */
                                                if (p->subs[ANALOG_SUB_THREEWAY].owner)
-                                                       ast_queue_hangup(p->subs[ANALOG_SUB_THREEWAY].owner);
+                                                       ast_queue_hangup_with_cause(p->subs[ANALOG_SUB_THREEWAY].owner, AST_CAUSE_NO_ANSWER);
                                                ast_softhangup_nolock(p->subs[ANALOG_SUB_THREEWAY].owner, AST_SOFTHANGUP_DEV);
                                                ast_debug(1, "Looks like a bounced flash, hanging up both calls on %d\n", p->channel);
                                                ast_channel_unlock(p->subs[ANALOG_SUB_THREEWAY].owner);
@@ -2427,6 +2339,7 @@ static struct ast_frame *__analog_handle_event(struct analog_pvt *p, struct ast_
                case ANALOG_SIG_FXOLS:
                case ANALOG_SIG_FXOGS:
                case ANALOG_SIG_FXOKS:
+                       p->fxsoffhookstate = 1;
                        switch (ast->_state) {
                        case AST_STATE_RINGING:
                                analog_set_echocanceller(p, 1);
@@ -2484,11 +2397,9 @@ static struct ast_frame *__analog_handle_event(struct analog_pvt *p, struct ast_
                case ANALOG_SIG_FXSLS:
                case ANALOG_SIG_FXSGS:
                case ANALOG_SIG_FXSKS:
-#if 0
                        if (ast->_state == AST_STATE_RING) {
                                p->ringt = p->ringt_base;
                        }
-#endif
 
                        /* Fall through */
                case ANALOG_SIG_EM:
@@ -2530,11 +2441,9 @@ static struct ast_frame *__analog_handle_event(struct analog_pvt *p, struct ast_
                case ANALOG_SIG_FXSLS:
                case ANALOG_SIG_FXSGS:
                case ANALOG_SIG_FXSKS:
-#if 0
                        if (ast->_state == AST_STATE_RING) {
                                p->ringt = p->ringt_base;
                        }
-#endif
                        break;
                }
                break;
@@ -2572,10 +2481,9 @@ static struct ast_frame *__analog_handle_event(struct analog_pvt *p, struct ast_
                case ANALOG_SIG_FXOLS:
                case ANALOG_SIG_FXOGS:
                case ANALOG_SIG_FXOKS:
-#if 0
                        ast_debug(1, "Winkflash, index: %d, normal: %d, callwait: %d, thirdcall: %d\n",
-                               index, p->subs[ANALOG_SUB_REAL].dfd, p->subs[ANALOG_SUB_CALLWAIT].dfd, p->subs[ANALOG_SUB_THREEWAY].dfd);
-#endif
+                               index, analog_get_sub_fd(p, ANALOG_SUB_REAL), analog_get_sub_fd(p, ANALOG_SUB_CALLWAIT), analog_get_sub_fd(p, ANALOG_SUB_THREEWAY));
+
                        p->callwaitcas = 0;
 
                        if (index != ANALOG_SUB_REAL) {
@@ -3045,6 +2953,7 @@ int analog_handle_init_event(struct analog_pvt *i, int event)
                case ANALOG_SIG_FXOGS:
                case ANALOG_SIG_FXOKS:
                        res = analog_off_hook(i);
+                       i->fxsoffhookstate = 1;
                        if (res && (errno == EBUSY))
                                break;
                        if (i->immediate) {
@@ -3083,9 +2992,7 @@ int analog_handle_init_event(struct analog_pvt *i, int event)
                case ANALOG_SIG_FXSLS:
                case ANALOG_SIG_FXSGS:
                case ANALOG_SIG_FXSKS:
-#if 0
                                i->ringt = i->ringt_base;
-#endif
                                /* Fall through */
                case ANALOG_SIG_EMWINK:
                case ANALOG_SIG_FEATD:
@@ -3139,16 +3046,15 @@ int analog_handle_init_event(struct analog_pvt *i, int event)
                break;
        case ANALOG_EVENT_ALARM:
                i->inalarm = 1;
-#if 0
-               res = get_alarms(i);
-               handle_alarms(i, res);  
-#endif
+               analog_get_and_handle_alarms(i);
+
                /* fall thru intentionally */
        case ANALOG_EVENT_ONHOOK:
                /* Back on hook.  Hang up. */
                switch (i->sig) {
                case ANALOG_SIG_FXOLS:
                case ANALOG_SIG_FXOGS:
+                       i->fxsoffhookstate = 0;
                case ANALOG_SIG_FEATD:
                case ANALOG_SIG_FEATDMF:
                case ANALOG_SIG_FEATDMF_TA:
@@ -3172,6 +3078,7 @@ int analog_handle_init_event(struct analog_pvt *i, int event)
                        analog_on_hook(i);
                        break;
                case ANALOG_SIG_FXOKS:
+                       i->fxsoffhookstate = 0;
                        analog_set_echocanceller(i, 0);
                        /* Diddle the battery for the zhone */
 #ifdef ZHONE_HACK
@@ -3244,7 +3151,6 @@ struct analog_pvt * analog_new(enum analog_sigtype signallingtype, struct analog
        p->chan_pvt = private_data;
 
        /* Some defaults for values */
-       p->sendcalleridafter = 1;
        p->cid_start = ANALOG_CID_START_RING;
        p->cid_signalling = CID_SIG_BELL;
        /* Sub real is assumed to always be alloc'd */
index 6611798..89ac6b8 100644 (file)
@@ -185,6 +185,13 @@ struct analog_callback {
        /* callbacks for increasing and decreasing ss_thread_count, will handle locking and condition signal */
        void (* const increase_ss_count)(void);
        void (* const decrease_ss_count)(void);
+
+       int (* const distinctive_ring)(struct ast_channel *chan, void *pvt, int idx, int *ringdata);
+       int (* const set_linear_mode)(void *pvt, int idx, int linear_mode);
+       void (* const get_and_handle_alarms)(void *pvt);
+       void * (* const get_sigpvt_bridged_channel)(struct ast_channel *chan);
+       int (* const get_sub_fd)(void *pvt, enum analog_sub sub);
+       void (* const set_cadence)(void *pvt, int *cidrings, struct ast_channel *chan);
 };
 
 
@@ -210,8 +217,12 @@ struct analog_pvt {
        /* All members after this are giong to be transient, and most will probably change */
        struct ast_channel *owner;                      /*!< Our current active owner (if applicable) */
 
-       struct analog_subchannel subs[3];                       /*!< Sub-channels */
+       struct analog_subchannel subs[3];               /*!< Sub-channels */
        struct analog_dialoperation dop;
+       int onhooktime;                                                 /*< Time the interface went on-hook. */
+       int fxsoffhookstate;                                    /*< TRUE if the FXS port is off-hook */
+       /*! \brief -1 = unknown, 0 = no messages, 1 = new messages available */
+       int msgstate;
 
        /* XXX: Option Variables - Set by allocator of private structure */
        unsigned int answeronpolarityswitch:1;
@@ -228,17 +239,22 @@ struct analog_pvt {
        unsigned int transfer:1;
        unsigned int transfertobusy:1;                  /*!< allow flash-transfers to busy channels */
        unsigned int use_callerid:1;                    /*!< Whether or not to use caller id on this channel */
+       const struct ast_channel_tech *chan_tech;
+       /*!
+     * \brief TRUE if distinctive rings are to be detected.
+     * \note For FXO lines
+     * \note Set indirectly from the "usedistinctiveringdetection" value read in from chan_dahdi.conf
+     */
+       unsigned int usedistinctiveringdetection:1;
 
        /* Not used for anything but log messages.  Could be just the TCID */
-       int channel;                                    /*!< Channel Number or CRV */
+       int channel;                                    /*!< Channel Number */
        enum analog_sigtype outsigmod;
        int echotraining;
        int cid_signalling;                             /*!< Asterisk callerid type we're using */
        int polarityonanswerdelay;
        int stripmsd;
        enum analog_cid_start cid_start;
-       /* Number of rings to wait to send callerid on FXS.  Set to 1 for US */
-       int sendcalleridafter;
        int callwaitingcallerid;
        char mohsuggest[MAX_MUSICCLASS];
        char cid_num[AST_MAX_EXTENSION];
@@ -282,10 +298,8 @@ struct analog_pvt {
 
        int callwaitcas;
 
-#if 0
        int ringt;
        int ringt_base;
-#endif
 };
 
 struct analog_pvt * analog_new(enum analog_sigtype signallingtype, struct analog_callback *c, void *private_data);